设计模式——适配器模式

1. 定义

适配器模式(Adapter Pattern)属于结构型设计模式,它的主要作用是将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。简单来说,就是充当了不同接口之间的 "转换器" 或 "适配器",让原本不匹配的双方能够顺利对接。

2. 结构组成

适配器模式通常包含以下几个关键角色:

  • 目标接口(Target Interface):
    这是客户所期望的接口,客户端代码通过这个接口来调用相关功能。它定义了客户端想要使用的方法签名等。例如,在一个图形绘制系统中,客户端期望调用 draw() 方法来绘制图形,那么目标接口中就会定义这个 draw() 方法。
  • 被适配者(Adaptee):
    它是已经存在的、具有某些功能但接口不符合客户端要求的类或对象。比如,有一个第三方图形库提供了 displayShape() 方法来展示图形,但其接口与客户端期望的 draw() 接口不同,这个第三方图形库就是被适配者。
  • 适配器(Adapter):
    适配器类实现了目标接口,并持有对被适配者的引用。在适配器类的方法实现中,会调用被适配者的相关方法,并将其结果转换为符合目标接口要求的形式返回给客户端。例如,在上述图形绘制场景中,适配器类会在自己实现的 draw() 方法里调用第三方图形库的 displayShape() 方法,并做一些必要的适配处理,使得客户端能像调用自己期望的 draw() 方法一样来使用第三方图形库的功能。

3. 类图示例

  • 组合 +继承
  • 多重继承
  1. 客户端 (Client) 是包含当前程序业务逻辑的类。
  2. 客户端接口 (Client Interface) 描述了其他类与客户端代码合作时必须遵循的协议。
  3. 服务 (Service) 中有一些功能类 (通常来自第三方或遗留系统)。 客户端与其接口不兼容, 因此无法直接调用其功能。
  4. 适配器 (Adapter) 是一个可以同时与客户端和服务交互的类: 它在实现客户端接口的同时封装了服务对象。 适配器接受客户端通过适配器接口发起的调用, 并将其转换为适用于被封装服务对象的调用。
  5. 客户端代码只需通过接口与适配器交互即可, 无需与具体的适配器类耦合。 因此, 你可以向程序中添加新类型的适配器而无需修改已有代码。 这在服务类的接口被更改或替换时很有用: 你无需修改客户端代码就可以创建新的适配器类。

4. 示例代码

  1. 组合 + 继承
cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
#include <memory>

using namespace std;


class ClientInterface{
public:
    ClientInterface(){cout << "ClientInterface construct" <<endl;}
    virtual ~ClientInterface(){cout << "ClientInterface destruct" <<endl;}
    
    virtual string request() const{
        return  "ClientInterface: The default ClientInterface's behavior.";
    }
};

class Service{
public:
    Service(){cout << "Service construct" <<endl;}
    virtual ~Service(){cout << "Service destruct" <<endl;}
    
    string SpecialRequest()const{
        return "5 4 3 2 1";
    }
    
};

class Adapter : public ClientInterface{
private:
    shared_ptr<Service> _service;
public:
    Adapter( shared_ptr<Service> service): _service(service){cout << "Adapter construct" <<endl;}
    virtual ~Adapter(){cout << "Adapter destruct" <<endl;}
    
    string request() const override{
        string to_reverse = _service->SpecialRequest();
        reverse(to_reverse.begin(),to_reverse.end());
        return to_reverse;
    }
};

void Client(const shared_ptr<ClientInterface>& cinter){
    cout<< "Client: " << cinter->request()<<endl;
}

int main(){
    cout << "Client: I can work just fine with the ClientInterface  objects:\n";
    shared_ptr<ClientInterface> cinter = make_shared<ClientInterface>();
    Client(cinter);
    cout<< "\n\n";
    
    
    shared_ptr<Service> service = make_shared<Service>();
    cout << "Client: The Service class has a weird interface. See, I don't understand it:\n";
    cout << "Service: " << service->SpecialRequest();
    cout << "\n\n";
    
    cout << "Client: But I can work with it via the Adapter:\n";
    shared_ptr<Adapter> adapter = make_shared<Adapter>(service);
    Client(adapter);
    std::cout << "\n";
    
    return 0;
}
  1. 多重继承
cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
#include <memory>

using namespace std;


class ClientInterface{
public:
    ClientInterface(){cout << "ClientInterface construct" <<endl;}
    virtual ~ClientInterface(){cout << "ClientInterface destruct" <<endl;}
    
    virtual string request() const{
        return  "ClientInterface: The default ClientInterface's behavior.";
    }
};

class Service{
public:
    Service(){cout << "Service construct" <<endl;}
    virtual ~Service(){cout << "Service destruct" <<endl;}
    
    string SpecialRequest()const{
        return "5 4 3 2 1";
    }
    
};

class Adapter : public ClientInterface , public Service{
public:
    Adapter(){cout << "Adapter construct" <<endl;}
    virtual ~Adapter(){cout << "Adapter destruct" <<endl;}
    
    string request() const override{
        string to_reverse = SpecialRequest();
        reverse(to_reverse.begin(),to_reverse.end());
        return to_reverse;
    }
};

void Client(const shared_ptr<ClientInterface>& cinter){
    cout<< "Client: " << cinter->request()<<endl;
}

int main(){
    cout << "Client: I can work just fine with the ClientInterface  objects:\n";
    shared_ptr<ClientInterface> cinter = make_shared<ClientInterface>();
    Client(cinter);
    cout<< "\n\n";
    
    
    shared_ptr<Service> service = make_shared<Service>();
    cout << "Client: The Service class has a weird interface. See, I don't understand it:\n";
    cout << "Service: " << service->SpecialRequest();
    cout << "\n\n";
    
    cout << "Client: But I can work with it via the Adapter:\n";
    shared_ptr<Adapter> adapter = make_shared<Adapter>();
    Client(adapter);
    std::cout << "\n";
    
    return 0;
}

5. 模式优势体现

  • 提高复用性:通过适配器模式,Service类无需进行修改就可以在ClientInterface的接口体系下被复用,避免了对已有代码的大量改动。
  • 增强扩展性:如果后续有更多不同接口的类需要与客户端代码集成,只需要创建相应的适配器类,而不需要对客户端代码和已有类进行大规模的重构,符合开闭原则,使得系统具有更好的扩展性。
  • 解耦客户端与具体实现:客户端只需要依赖ClientInterface接口,而不需要了解具体的Service类或其他被适配类的细节,降低了代码的耦合度,提高了代码的可维护性和可理解性。

6. 总结

适配器模式在这个代码示例中有效地解决了ClientInterface与Service类之间的接口不兼容问题,通过创建适配器类,将Service类的功能适配到客户端期望的接口形式,使得整个系统更加灵活、可扩展和易于维护,是一种在软件设计中非常实用的设计模式,尤其适用于系统集成和接口转换的场景。

相关推荐
晚秋贰拾伍1 小时前
设计模式的艺术-代理模式
运维·安全·设计模式·系统安全·代理模式·运维开发·开闭原则
Cikiss1 小时前
「全网最细 + 实战源码案例」设计模式——简单工厂模式
java·后端·设计模式·简单工厂模式
新与2 小时前
设计模式:责任链模式——行为型模式
设计模式·责任链模式
等一场春雨2 小时前
Java设计模式 六 原型模式 (Prototype Pattern)
java·设计模式·原型模式
程序研11 小时前
JAVA之外观模式
java·设计模式
博一波14 小时前
【设计模式-行为型】观察者模式
观察者模式·设计模式
等一场春雨14 小时前
Java设计模式 十二 享元模式 (Flyweight Pattern)
java·设计模式·享元模式
rolt18 小时前
电梯系统的UML文档07
设计模式·产品经理·架构师·uml
等一场春雨1 天前
Java设计模式 十 装饰模式 (Decorator Pattern)
java·设计模式·装饰器模式
等一场春雨1 天前
Java 设计模式 二 单例模式 (Singleton Pattern)
java·单例模式·设计模式