Kac*_*kao 3 c++ design-patterns wrapper
我必须使用一个界面非常笨拙的旧类。由于我无法更改它并且依赖它,因此我想构建一个包装器,提供一个干净的界面。假设我有一堂课ClumsyClass。基本上,我有三种方法:
1. 参考会员
Class Wrapper {
public:
Wrapper (ClumsyClass& clumsyClass)
: m_clumsyClass(clumsyClass)
{ }
int getSmth() {
return m_clumsyClass.getSmth();
}
private:
ClumsyClass& m_clumsyClass;
}
Run Code Online (Sandbox Code Playgroud)
2. 指针成员
Class Wrapper {
public:
Wrapper (ClumsyClass* clumsyClass)
: m_clumsyClass(clumsyClass)
{ }
int getSmth() {
return m_clumsyClass->getSmth();
}
private:
ClumsyClass* m_clumsyClass;
}
Run Code Online (Sandbox Code Playgroud)
3、继承
Class Wrapper : public ClumsyClass {
...
}
Run Code Online (Sandbox Code Playgroud)
哪种方法是实现包装器的“最干净”方法?我更喜欢第三个,但是当我已经有一个 ClumsyClass 对象然后创建一个 Wrapper 对象(复制构造函数)时,将需要更多内存(因为在我的情况下需要原始类的实例)。
我会避免使用 3,因为它无法封装ClumsyClass. 用户可以Wrapper有意或无意地直接访问“笨拙”的界面,而ClumsyClass这正是您试图避免的。优先选择组合而不是继承。
1. 和 2. 之间的差异很小。使用参考构件会降低包装器的灵活性。该类不可分配,您无法重新设置引用并将其替换为不同的实例,ClumsyClass并且成员不能为空。这些可能是好事也可能是坏事,具体取决于您的要求。
但正如评论中提到的,默认选择可能应该是作为 的ClumsyClass按值成员Wrapper:
class Wrapper {
public:
// possible constructors
//Wrapper(const ClumsyClass& cc) : m_clumsyClass(cc) {} // copy
//Wrapper(ClumsyClass&& cc) : m_clumsyClass(std::move(cc)) {} // move
int getSmth() { return m_clumsyClass.getSmth(); }
private:
ClumsyClass m_clumsyClass;
};
Run Code Online (Sandbox Code Playgroud)
在您的特定用例中,有多种原因可能导致这种情况不可能或不理想,然后您可以回退到选项 1 或 2。该决定主要取决于所有权。是否应该Wrapper“拥有”ClumsyClass或 的实例是否ClumsyClass具有超出 的生命周期Wrapper?
使用直接成员的一个潜在缺点是您无法再隐藏ClumsyClass前向声明后面的实现,因此您会失去一些ClumsyClass. 值得注意的是,解决这个问题的一种方法是提取一个Wrapper继承自的抽象基类“接口”。就像是:
class IWrapper {
public:
virtual ~IWrapper() {}
virtual int getSmth() = 0;
};
Run Code Online (Sandbox Code Playgroud)
这可能会提供额外的好处,例如可测试性。