C++中的设计问题:以界面为中心的设计中的代码重用
Design issue in C++: code reuse in interface centric design
该项目有一个目标:使用以界面为中心的设计。基本上,我们只声明公共纯函数的类,并让实类继承自它们。
现在出现了一个问题 - 如何重用实用程序函数?
下面是一个示例:
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)我可以像这样将受保护添加到接口类中:
class InterF1 {
public:
int f1() = 0;
int g1() = 0;
protected:
int util();
int convenient_var_calculated_by_util;
};
在上面的设计中,C1::f1() 和 C2::f2() 都可以调用 util()。
2)我可以抽象一个新的接口:
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 更高级别的抽象,后者更多的是实现细节,我是否混合了 2 个级别?换句话说,如果以后实现发生变化,我将需要再次回来更新 f1() 和 f2() 签名,这听起来不对。
解决方案 1 看起来确实很方便,但对我来说看起来不那么"纯粹",我在这里是不是太教条了?
说你应该把公共实现放在基类中 - 但你要求基类是纯虚拟的。 因此,我建议
:创建中间实现类
如果每个想要实现
InterF2
的类也想实现InterF1
,则此方法是可以的。方法是实施
class InterF1Impl: public InterF1 { public: int f1(); int g1(); }
然后,
C1
和C2
都可以从实现常见f1()
和g1()
方法的InterF1Impl
派生。但是,如果您有另一个类
C3 : public InterF2
,则此方法不会很好地扩展,该类希望与C2
共享f2()
的实现,但不想实现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
如果你以后需要这样的类。
您的第二个解决方案比第一个解决方案更好,但我会以不同的方式做。
首先,代码重用可以通过对象之间的继承或组合关系来实现。在这种情况下,组合方法更有意义,正如我在下面解释的那样。
类的用户可能不关心 util()
方法的实现,甚至不关心它的存在。因此,拥有UtilI
接口并使其成为公共 API 的一部分似乎没有必要。由于实用程序逻辑是实现的一部分,而不是接口的一部分,因此此类应仅用于 C1 和 C2 类的实现。如果你这样做,你可能不需要UtilI
接口,可以只用具体的类Util
替换。您可能可以使此类无状态,以便它只有静态方法。如果不是,那么它可以是单例,或者您的类可以创建自己的实例(取决于您的需要)。
以接口为中心的设计是一个很好的目标,但重要的是只公开应该公开的内容。这是设计任何 API 的重要组成部分,它应该是完整和最小的。
- 创建LinkedList退出,返回代码为-11(SIGSEGV)
- Netbeans 10:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- 链接器命令失败,macOS 上的退出代码为 1(使用 -v 查看调用)
- 你好世界在 APUE 第 7 章退出,代码为 0
- VSCode C++终端进程已终止,退出代码为:1
- CMake 错误:链接器命令失败,退出代码为 1 和 cpp.o 文件
- clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用) - 体系结构的未定义符号 x86_64:
- 如何修复 clang: 错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- CLion、MinGW 和 SDL2:进程已完成,退出代码为 -1073741515 (0xC0000135)
- Xcode:链接器命令失败,退出代码为 1(使用 -v 查看调用)[C++]
- Android NDK.Build命令失败.未定义的引用.clang++:错误:链接器命令失败,退出代码为1
- 如何从支持linux/mac操作系统的第三方代码为我的c#项目创建dll
- 终端进程终止,退出代码为:1有什么方法可以修复它吗
- 运行自定义可执行文件,QProcess 立即退出,退出代码为 1
- 错误:链接器命令失败,退出代码为 1(使用 -v 查看调用):在 Macbook 上
- C++ XCODE ld:找不到体系结构x86_64 clang 的符号:错误:链接器命令失败,退出代码为 1(使用 -
- 为什么我的代码为同一代码生成不同的值
- clang:错误:链接器命令失败,C++代码中的退出代码为 1(使用 -v 查看调用)
- OpenGL 应用程序退出,退出代码为 -1073741515 (0xC0000135)
- C++中的设计问题:以界面为中心的设计中的代码重用