有人会如何解决类的问题,并尽可能少地输入代码? 这就是我所拥有的
一切的基础界面
class IWindow
{
public:
virtual void Refresh() = 0;
// another 100 virtual methods
// ...
};
此接口用于不知道具体实现的库中。
以下是具体实现的一个版本
class ConcreteWindow : public IWindow
{
public:
void Refresh() override {}
/// the other 100 overridden methods
};
现在我们有另一个接口,它添加了一些额外的方法,并且也在该库中使用。
class IDBDetail : public IWindow
{
public:
virtual void DoDetail() = 0;
};
这是主要的问题,当我们为它创建具体的实现时
class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow
{
public :
void DoDetail() {}
};
当然具体课程IGDBDetailWrapper
也是抽象的,因为它没有实现这100种方法,但我不想这样做,我只想重用来自ConcreteWindow
的实现,它们都使用相同的窗口句柄,但当然不会编译。
我可以将这100个方法从ConcreteWindow
复制/粘贴到IGDBDetailWrapper
,但这太过分了,因为我可能还有另外10个这样的新接口和具体实现。
我可以在这里使用哪种其他模式来帮助解决问题而不是一次又一次地重新实现这100种方法?
THX
答案 0 :(得分:3)
您的设计已遇到diamond problem。
现在我们有另一个接口添加一些额外的方法和 也在该库中使用。
class IDBDetail : public IWindow {
public:
virtual void DoDetail() = 0;
};
从IDBDetail接口的描述看起来,IDBDetail不应该继承自IWindow。如果它只是添加额外的功能,那么IDBDetail不一定是IWindow。它只需要了解IWindow。例如,为了让猴子做一些特殊的事情,训练师不一定是猴子。
Decorator pattern可能正是您要找的。
答案 1 :(得分:3)
首先,如果您使用的是Visual Studio,那么有一些重构工具可以帮助您实现自动化,这可能是一项繁琐的工作,第二步:
对我而言,做同样的事情是毫无意义的:
class IDBDetail : public IWindow
{
public:
virtual void DoDetail() = 0;
};
我会这样做
class IDBDetail
{
public:
virtual void DoDetail() = 0;
};
应该使用接口来抽象出责任,因此使用其他方法将已有数百种方法混杂在一起的界面是设计糟糕的症状。
但是,您可以一次性使用合成,因此您可以创建一个时间来解决您的问题,然后您可以重新使用
class IDBDetailWithConcreteWindow: public IDBDetail{
IWindow * concreteWindow;
public:
IDBDetailWithConcreteWindow(IWindow * window){
concreteWindow = window;
}
void Refresh() override{
concreteWindow->Refresh();
}
}
最后在任何派生类中,您只需要实现IDBDetail
中的方法IGDBDetailWrapper: public IDBDetailWithConcreteWindow{
public:
void DoDetail() override { }
}
此解决方案的优势在于,如果您有外部约束(如设计不良的预先存在的代码库),您仍然可以使用它,而如果您无法更改IDBDetail接口,则上层解决方案将无效。
答案 2 :(得分:3)
@bashrc是对的,但应该可以解决虚拟继承的问题:
class ConcreteWindow : public virtual IWindow {...}
class IDBDetail : public virtual IWindow {...}
关于virtual inheritance的维基百科文章也说明了解决方案。
答案 3 :(得分:2)
你必须覆盖抽象类中的所有方法,没有其他方法。实际上你不应该在这里创建一个100方法的抽象类,就是这样。也许你可以把它分成一些较小的抽象类?但是,在这种情况下,IDBDetail不应该在IWindow之后继承,IGBDDetailWrapper也不应该在IWindow之后继承 - 我们就在这里。
答案 4 :(得分:2)
它无法解决您的问题,但至少您可以自行重定向执行:
class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow
{
public:
virtual void DoDetail() override { /*work here*/ }
virtual void Refresh() override { ConcreteWindow::Refresh(); }
//another 100 methods
};
您可以将此类重定向阻止为编译器#DEFINE
,并根据需要重复多次。
答案 5 :(得分:2)
您可以使用虚拟继承。如果我们忽略IDBDetail
从IWindow
继承的事实,我们可以使用虚拟继承来解决当前架构的问题:
class IWindow
{
public:
virtual void Refresh() = 0;
// another 100 virtual methods
// ...
};
class ConcreteWindow : virtual public IWindow
{
public:
void Refresh() override {}
/// the other 100 overridden methods
};
class IDBDetail : virtual public IWindow
{
public:
virtual void DoDetail() = 0;
};
class IGDBDetailWrapper : public IDBDetail, public ConcreteWindow
{
public :
void DoDetail() {}
};
现在编译器将使用来自ConcreteWindow