C++设计模式——适配器模式(Adapter Pattern)

C++设计模式——适配器模式(Adapter Pattern)

微信公众号:幼儿园的学霸

目录

文章目录

  • C++设计模式——适配器模式(Adapter Pattern)
  • 目录
  • 定义
    • 定义
    • 作用/解决的问题
    • 适配器模式中的角色
  • 代码示例
  • 总结
    • 优缺点
    • 适用场景
  • 参考资料

定义

定义

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
将两个不相兼容的接口通过适配器进行相互转化。

适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。

根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。

作用/解决的问题

它的主要作用是在新接口和老接口之间进行适配。我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。

适配器模式中的角色

Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。该角色把其他类转换为我们期望的接口

Adapter(适配器类):将被适配者和目标接口组合到一起的类,适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。

Adaptee(适配者类,被适配者):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,也是希望被改变的接口,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
其UML类图如下:
C++设计模式——适配器模式(Adapter Pattern)_第1张图片

思考一个问题:适配器模式中,用到了接口继承?用到了实现继承?什么是接口继承和实现继承?两者有什么区别和联系?
接口继承: 派生类只继承函数接口,也就是声明。
实现继承:派生类同时继承函数的接口和实现。

代码示例

以美式电源接头和国标之间的转换为例,进行说明,代码如下,分别有类适配器模式和对象适配器模式

#include 

//
//类适配器
//


//Adaptee 被适配者类.现有的类
//比如有美式插座、欧式插座、日式插座
class USOutlet {
public:
    void type() {
        std::cout << "using US outlet !" << std::endl;
    }
};


//Target 抽象目标类
//我们想用的国标类型
class CNOutlet {
public:
    virtual void use_CN_type() = 0;
};


//Adapter 适配类
//可以理解为转接头
//采用类适配器
class CNOutletAdapter : public CNOutlet, private USOutlet {
public:
    void use_CN_type() override {
        //do something convert
        std::cout << "adapter transfer CN to US outlet" << std::endl;
        type();

    }
};

//采用对象适配器
//采用将adaptee作为构造函数参数,类似的方式(如模板等)具有一定的灵活性
//可以选择性适配自己想适配的对象,和策略方式类似
class CNOutletAdapter_2 : public CNOutlet {
private:
    std::shared_ptr m_pUSOutlet;
public:
    CNOutletAdapter_2(std::shared_ptr pUSOutlet)
            : m_pUSOutlet(pUSOutlet) {

    }

    void use_CN_type() override {
        //do something convert
        std::cout << "adapter transfer CN to US outlet" << std::endl;
        m_pUSOutlet->type();
    }
};

//对象适配器方法2,将adaptee普通对象作为成员变量
//注意对比和上面对象适配器的区别
class CNOutletAdapter_3 : public CNOutlet {
private:
    USOutlet m_usoutlet;
public:
    void use_CN_type() override {
        //do something convert
        std::cout << "adapter transfer CN to US outlet" << std::endl;
        m_usoutlet.type();

    }
};


int main() {
    //类适配器
    std::shared_ptr pCNOUtlet = std::make_shared();
    pCNOUtlet->use_CN_type();
    //运行结果
    //adapter transfer CN to US outlet
    //using US outlet !

    //对象适配器
    CNOutletAdapter_2 cnOutletAdapter2(std::make_shared());
    cnOutletAdapter2.use_CN_type();
    //运行结果
    //adapter transfer CN to US outlet
    //using US outlet !

    return 0;
}

在代码中演示的对象适配器模式中,我们在构造的时候将具体需要适配的适配对象传入,这样便可以根据传入不同的对象,从而对该对象进行适配。而类适配器却无法选择对象,它是对整个类进行适配。

总结

优缺点

  • 优点:
    1.可以让任何两个没有关联的类一起运行;
    2.提高了类的复用。通过复用的现存的类, 解决了现存类和复用环境要不一致的问题;
    3.低耦合。将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码(遵循开闭原则)。
    4.增加了类的透明度。通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的; 5.针对类适配器模式,由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强;
    6.针对对象适配器模式,一个对象适配器可以把多个不同的适配者适配到同一个目标。

  • 缺点:
    1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
    2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

适用场景

1.系统需要使用现有的类,而这些类的接口不符合系统的接口要求;
2.两个类所做的事情相同或相似,但是具有不同接口的时候;

总的来说,适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。 此,为区分对象适配器模式和策略模式的重要区别。

参考资料

1.设计模式 | 适配器模式及典型应用



下面的是我的公众号二维码图片,欢迎关注。
图注:幼儿园的学霸

你可能感兴趣的:(C++,设计模式,c++)