设计模式——适配器模式

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 小时前
深入理解设计模式之代理模式
java·设计模式·代理模式
mjr3 小时前
设计模式-Java
java·设计模式
yuanpan3 小时前
23种设计模式之《组合模式(Composite)》在c#中的应用及理解
开发语言·设计模式·c#·组合模式
FLZJ_KL5 小时前
【设计模式】【创建型模式】单例模式(Singleton)
java·单例模式·设计模式
万兴丶7 小时前
Unity 适用于单机游戏的红点系统(前缀树 | 数据结构 | 设计模式 | 算法 | 含源码)
数据结构·unity·设计模式·c#
菜鸟一枚在这8 小时前
深入剖析抽象工厂模式:设计模式中的架构利器
设计模式·架构·抽象工厂模式
码熔burning8 小时前
(三)趣学设计模式 之 抽象工厂模式!
设计模式·抽象工厂模式
程序猿多布9 小时前
C#设计模式 学习笔记
设计模式·c#
強云13 小时前
23种设计模式 - 模板方法
设计模式·模板方法
workflower19 小时前
Prompt Engineering的重要性
大数据·人工智能·设计模式·prompt·软件工程·需求分析·ai编程