适配器模式可以将一种接口转换成另一种接口,主要用在解决兼容性问题。比如软件升级时,新旧API之间的兼容,使用第三方库时,两个或多个第三方库之间的兼容性问题等等。
举个例子,玩具厂生产一种鸭子Duck玩具,Duck有两个接口quack与fly如下
- class Duck {
- public:
- virtual void quack() {
- std::cout << "呱呱呱" << std::endl;
- }
- virtual void fly() {
- std::cout << "I am flying a long distance" << std::endl;
- }
- };
玩具管理对象调用duck.quack()和duck.fly()让玩具嘎嘎叫和飞一段距离。
有一天出现一种状况是鸭子对象没有了,只有火鸡Turk对象,turk不会嘎嘎叫,火鸡会飞,但没鸭子飞得远,火鸡类定义如下
- class Turkey {
- public:
- virtual void gooble() {
- std::cout << "嘎嘎嘎" << std::endl;
- }
- virtual void fly() {
- std::cout << "I am flying a short distance" << std::endl;
- }
- };
现在想用火鸡对象去冒充鸭子对象,但是呢接口不一致,不能直接使用,这时就需要用适配器。在适配器中用火鸡的咕咕叫gobble()来冒充鸭子的呱呱叫quack,让火鸡多飞几次来冒充鸭子的一次飞行。可以理解适配器是做一种转换,将被适配者的一个接口转换为另一个客户期待的接口,从而解决兼容性问题。
适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
类图如下
(图片链接:C++设计模式 - 适配器模式 - 知乎 (zhihu.com)侵删)
客户使用适配器的过程如下:
1、客户通过目标接口调用适配器的方法对适配器发出请求。
2、 适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口。
3、 客户收到调用的结果,但并未察觉这一切是适配器在起到转换作用。
针对需求场景中的例子,定义并实现TurkeyAdapter类,该类接收一个turkey对象,继承自Duck对象,并实现Duck对象的虚接口quack和fly,在接口中调用turkey对象的goobel和fly方法,具体代码如下
- class TurkeyAdapter :public Duck
- {
- public:
- TurkeyAdapter(Turkey* turkey):_turkey(turkey)
- {
-
- }
- virtual void quack() {
- _turkey->gooble();
- }
- virtual void fly() {
- for (int i = 0; i < 5; i++)
- {
- _turkey->fly();
- }
- }
- private:
- Turkey* _turkey;
- };
测试适配器的代码如下
- int main()
- {
- Duck* duck = new Duck();
- Turkey* turkey = new Turkey();
- Duck* turkeyAdapter = new TurkeyAdapter(turkey);
-
- std::cout << "Duck:" << std::endl;
- duck->quack();
- duck->fly();
- std::cout << std::endl;
-
- std::cout << "Turkey:" << std::endl;
- turkey->gooble();
- turkey->fly();
- std::cout << std::endl;
-
- std::cout << "turkeyAdapter:" << std::endl;
- turkeyAdapter->quack();
- turkeyAdapter->fly();
- std::cout << std::endl;
-
-
- delete duck;
- delete turkey;
- delete turkeyAdapter;
- return 0;
- }
运行效果如下
前面介绍的是对象适配器。对象适配器和类适配器的不同是,对象适配器使用组合的方式,持有一个被适配器对象。而类适配器是多重继承的方式,继承了目标接口类Target和被适配器类Adaptee。
类图如下:
(图片链接:C++设计模式 - 适配器模式 - 知乎 (zhihu.com)侵删)
上面那个例子如果有类适配器实现的话,代码如下
- class TurkeyAdapter :public Duck,public Turkey
- {
- public:
- virtual void quack() {
- gooble();
- }
- virtual void fly() {
- for (int i = 0; i < 5; i++)
- {
- Turkey::fly();
- }
- }
- };