设计模式——适配器模式

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类的功能适配到客户端期望的接口形式,使得整个系统更加灵活、可扩展和易于维护,是一种在软件设计中非常实用的设计模式,尤其适用于系统集成和接口转换的场景。

相关推荐
晨米酱15 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机20 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机21 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机21 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机21 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤21 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机2 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机2 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴2 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤2 天前
工厂模式
设计模式