[设计模式] 设计模式课程(十三)--适配器模式
概述
- 由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但新环境要求的接口是这些现存对象所不满足的
- 如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
- Adapter举例
- 将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作
- 继承:遵循你定义的接口规范(is-a)
- 组合:支持一个实现(has-a)
- Adapter继承Target,并通过指针指向Adaptee(组合),实现了从Adaptee到Target的转换
- 继承新接口,组合老接口
- 代码仅示意,实际转换方式可能很复杂
- 希望复用一些现存的类,但接口又与复用环境要求不一致的情况,在遗留代码复用、类库迁移等方面非常有用
- GOF 23 定义了两种Adapter模式:对象适配器(采用组合方案)、类适配器(采用多继承模式,不推荐使用,多继承和组合在内存模型上接近)
- public继承:公有接口,符合你的接口规范
- private、protected继承:实现继承,没继承接口但用你的实现(has-a)
- 类的成员(函数、变量)在内存层面是一种东西
- 私有继承的用法:父类的public和protected成员在子类中变成了子类的private成员
- 意味着从父类继承过来的这些成员(public/protected),子类的成员函数可以调用之,但子类的对象就不能调用之(派生类成员只能访问基类中public/protected成员,派生类对象不能访问基类中的任何成员)
- 即在子类中可以调用父类的接口(public/protected),但这些接口不会暴露出去,实现了包含(composite)的特性
- 相比类适配器,对象适配器灵活性更高(指针可以指向不同对象)
场景
- Java JDK 1.1使用了Enumeration接口,1.2中提供了Iterator接口,想要使用1.2 的JDK,则要讲以前系统的Enumeration接口转化为Iterator接口
- 在Linux上运行Windows程序
- Java中的jdbc
示例1
Adapter.cpp
1 //目标接口(新接口) 2 class ITarget{ 3 public: 4 virtual void process()=0; 5 }; 6 7 //遗留接口(老接口) 8 class IAdaptee{ 9 public: 10 virtual void foo(int data)=0; 11 virtual int bar()=0; 12 }; 13 14 //遗留类型 15 class OldClass: public IAdaptee{ 16 //.... 17 }; 18 19 //对象适配器 20 class Adapter: public ITarget{ //继承 21 protected: 22 IAdaptee* pAdaptee;//组合 23 24 public: 25 26 Adapter(IAdaptee* pAdaptee){ 27 this->pAdaptee=pAdaptee; 28 } 29 30 virtual void process(){ 31 int data=pAdaptee->bar(); 32 pAdaptee->foo(data); 33 34 } 35 }; 36 37 //类适配器 38 class Adapter: public ITarget, 39 protected OldClass{ //多继承 40 41 42 } 43 44 int main(){ 45 IAdaptee* pAdaptee=new OldClass(); 46 47 48 ITarget* pTarget=new Adapter(pAdaptee); 49 pTarget->process(); 50 51 52 } 53 54 class stack{ 55 deqeue container; 56 57 }; 58 59 class queue{ 60 deqeue container; 61 62 };
示例2
1 #include <string> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 6 class Target { 7 public: 8 virtual ~Target() = default; 9 10 virtual string Request() const { 11 return "Target: The default target's behavior."; 12 } 13 }; 14 15 /** 16 * The Adaptee contains some useful behavior, but its interface is incompatible 17 * with the existing client code. The Adaptee needs some adaptation before the 18 * client code can use it. 19 */ 20 class Adaptee { 21 public: 22 string SpecificRequest() const { 23 return ".eetpadA eht fo roivaheb laicepS"; 24 } 25 }; 26 27 /** 28 * The Adapter makes the Adaptee's interface compatible with the Target's 29 * interface. 30 */ 31 class Adapter : public Target { 32 private: 33 Adaptee *adaptee_; 34 35 public: 36 Adapter(Adaptee *adaptee) : adaptee_(adaptee) {} 37 string Request() const override { 38 string to_reverse = this->adaptee_->SpecificRequest(); 39 reverse(to_reverse.begin(), to_reverse.end()); 40 return "Adapter: (TRANSLATED) " + to_reverse; 41 } 42 }; 43 44 /** 45 * The client code supports all classes that follow the Target interface. 46 */ 47 void ClientCode(const Target *target) { 48 std::cout << target->Request(); 49 } 50 51 int main() { 52 std::cout << "Client: I can work just fine with the Target objects:\n"; 53 Target *target = new Target; 54 ClientCode(target); 55 std::cout << "\n\n"; 56 Adaptee *adaptee = new Adaptee; 57 std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:\n"; 58 std::cout << "Adaptee: " << adaptee->SpecificRequest(); 59 std::cout << "\n\n"; 60 std::cout << "Client: But I can work with it via the Adapter:\n"; 61 Adapter *adapter = new Adapter(adaptee); 62 ClientCode(adapter); 63 std::cout << "\n"; 64 65 delete target; 66 delete adaptee; 67 delete adapter; 68 69 return 0; 70 }
参考
UML图
https://www.cnblogs.com/jiangds/p/6596595.html
protected成员
http://c.biancheng.net/view/252.html
私有成员:只能在类内使用
保护成员:类内,继承类内可以使用
共有成员:所有地方都可使用
私有继承:父类成员继承后变为子类私有成员
保护继承:父类公有成员继承后变为子类保护成员
共有继承:父类成员继承后属性不变