diff --git a/07_adapter.cpp b/07_adapter.cpp new file mode 100644 index 0000000..6723f68 --- /dev/null +++ b/07_adapter.cpp @@ -0,0 +1,47 @@ +#include +#include + +using namespace std; + +class Target { + string s; +public: + Target(string s) : s(s) {} + virtual ~Target() = default; + + virtual void request(const string& contents) { + cout << s << " send request to server: " << contents << endl; + } +}; + +class Adaptee { +public: + int value; + Adaptee(int value) : value(value) {} +}; + +class Adapter : public Target { + shared_ptr a; +public: + Adapter(shared_ptr a) : + Target("User " + to_string(a->value)), a(a) {} + + virtual void request(const string& contents) override { + cout << "Adapted request" << endl; + Target::request(contents); + } +}; + + +int main() { + shared_ptr t = make_shared("User A"); + t->request("Hello"); + + shared_ptr adaptee = make_shared(42); + // Obviously this is invalid. + // a->request(); + + // But it works with adapter. + shared_ptr adapter = make_shared(adaptee); + adapter->request("Bye"); +} diff --git a/notes.md b/notes.md index 96d4f21..74ebb63 100644 --- a/notes.md +++ b/notes.md @@ -39,3 +39,13 @@ 有时需要在项目中创建副本,那么如何创建重复对象?很容易想到使用复制或赋值操作符,而不是普通的构造函数。但是这些方法没有多态性,如果很多子类需要复制就会有点麻烦。 解决方案也很简单,父类提供一种 `clone` 方法。这样客户端只需要调用 `clone` 方法,不需要知道这个类具体是什么。这种方法常配合对象注册表使用,通过维护一个原型缓存容器(如`map`),根据名字/类型复制对象。 + +## 适配器模式(Adapter) + +在开发过程中,可能会遇到接口不兼容的情况。例如,类 `A` 有一个向服务器发送请求的接口,而类 `B` 也需要实现类似的功能,但它并不继承自 `A`,因此无法通过多态方式调用 `A` 的接口。 + +一种解决方法是让 `B` 继承 `A`,这是一个很推荐的做法,但是这样做并不总是可行的,特别是当 `B` 是由他人设计或无法修改时。此时,可以设计一个适配器类。 + +适配器类可以继承自 `A`,并将 `B` 作为构造参数。在构造过程中,适配器将 `B` 的接口转换为符合 `A` 的接口形式。这样,通过适配器,`B` 就可以像 `A` 一样调用接口,达到接口兼容的效果。考虑到适配性,比如希望这个适配器类还能适配其他的 `C`,`D` 等,可以让适配器类接受一个更普遍的共性作为构造参数。 + +需要注意的是,这种做法显然会使得代码复杂很多,条件允许的话,还是直接修改 `B` 类较好。