该项目的目标是:使用以界面为中心的设计。基本上,我们声明仅公共(public)纯函数的类,并从它们继承真实的类。
现在出现一个问题-如何重用实用程序功能?
这是一个例子:
class InterF1 {
public:
int f1() = 0;
int g1() = 0;
};
class InterF2 {
public:
int f2() = 0;
};
class C1: public InterF1 {
public:
int f1();
int g1();
};
class C2: public InterF1, InterF2 {
public:
int f1();
int g1();
int f2();
};
当我实现C1::f1()和C2::f1()时,我看到这两个函数之间的代码重复。我应该如何删除重复项?
这是我的想法:
1)我可以像这样向接口(interface)类添加保护:
class InterF1 {
public:
int f1() = 0;
int g1() = 0;
protected:
int util();
int convenient_var_calculated_by_util;
};
在上述设计中,C1::f1()和C2::f2()都可以调用util()。
2)我可以抽象一个新接口(interface):
class UtilI {
public:
int util(int in_var) = 0;
};
在此设计中,将InterF1,C1和C2更改为
class InterF1 {
public:
int f1(UtilI u) = 0;
int g1() = 0;
};
class C1: public InterF1 {
public:
int f1(UtilI u);
int g1();
};
class C2: public InterF1, InterF2 {
public:
int f1(UtilI u);
int g1();
int f2();
};
C1::f1()和C2::f1()都调用UtilI API。
解决方案2似乎更符合我们的“以界面为中心”的目标,而且看起来确实更好。但是我有一个担忧,InterF1和InterF2本身应该比UtilI更高级别的抽象,后者是实现细节的更多内容,我是否将这两个级别混合在一起?换句话说,如果以后更改实现,我将需要再次更新f1()和f2()签名,这听起来不对。
解决方案1似乎很方便,但对我来说似乎不那么“纯粹”,我在这里教条太多吗?
最佳答案
通常,我会说您应该将通用实现放在基类中-但是您有一个要求,即基类是纯虚拟的。因此,我建议:
如果每个想要实现
InterF2
的类也都想实现InterF1
,则这种方法是可行的。方法是实现
class InterF1Impl: public InterF1 {
public:
int f1();
int g1();
}
然后
C1
和C2
都可以从InterF1Impl
派生,后者实现了常见的f1()
和g1()
方法。但是,如果您有另一个类
C3 : public InterF2
,则该方法不能很好地扩展,该类希望与f2()
共享C2
的实现,但又不想实现InterF1
。另一种(更好的)方法是
在这种方法中,如上所述实现
InterF1Impl: public InterF1
,但是不要派生C1: public InterF1Impl
,而是让InterF1Impl
作为C1
类的一部分。class C1: public InterF1 {
private:
InterF1Impl * f1impl;
public:
int f1();
int g1();
}
C1::f1()
和C1::g1()
方法仅从f1impl
调用相应的方法。这样,如果您需要
f2()
的通用实现,则还可以实现InterF2: public InterF2
,并且C2
可以通过类似的方式实现:class C2: public InterF1, InterF2 {
private:
InterF1Impl * f1impl;
InterF2Impl * f2impl;
public:
int f1(); /* calls f1impl->f1() */
int g1(); /* calls f1impl->g1() */
int f2(); /* calls f2impl->f2() */
}
如果您以后需要此类,则另一个类可以仅使用
InterF2
的实现,而无需也实现InterF1
。