• [设计模式] 设计模式课程(十三)--适配器模式


    概述

    • 由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但新环境要求的接口是这些现存对象所不满足的
    • 如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
    • 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 };
    View Code

    示例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:
    ";
    53   Target *target = new Target;
    54   ClientCode(target);
    55   std::cout << "
    
    ";
    56   Adaptee *adaptee = new Adaptee;
    57   std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:
    ";
    58   std::cout << "Adaptee: " << adaptee->SpecificRequest();
    59   std::cout << "
    
    ";
    60   std::cout << "Client: But I can work with it via the Adapter:
    ";
    61   Adapter *adapter = new Adapter(adaptee);
    62   ClientCode(adapter);
    63   std::cout << "
    ";
    64 
    65   delete target;
    66   delete adaptee;
    67   delete adapter;
    68 
    69   return 0;
    70 }
    View Code

    参考 

    UML图

    https://www.cnblogs.com/jiangds/p/6596595.html

    protected成员

    http://c.biancheng.net/view/252.html

    私有成员:只能在类内使用

    保护成员:类内,继承类内可以使用

    共有成员:所有地方都可使用 

    私有继承:父类成员继承后变为子类私有成员

    保护继承:父类公有成员继承后变为子类保护成员

    共有继承:父类成员继承后属性不变

  • 相关阅读:
    VS2010/MFC编程入门之十四(对话框:向导对话框的创建及显示)
    VS2010/MFC编程入门之十三(对话框:属性页对话框及相关类的介绍)
    Tomcat架构解析(四)-----Coyote、HTTP、AJP、HTTP2等协议
    Tomcat架构解析(三)-----Engine、host、context解析以及web应用加载
    Tomcat架构解析(二)-----Connector、Tomcat启动过程以及Server的创建过程
    Tomcat架构解析(一)-----Tomcat总体架构
    springboot深入学习(四)-----spring data、事务
    springboot深入学习(三)-----tomcat配置、websocket
    springboot深入学习(二)-----profile配置、运行原理、web开发
    springboot深入学习(一)-----springboot核心、配置文件加载、日志配置
  • 原文地址:https://www.cnblogs.com/cxc1357/p/12313115.html
Copyright © 2020-2023  润新知