精华内容
下载资源
问答
  • C++ 适配器模式

    千次阅读 热门讨论 2017-03-27 16:44:21
    适配器模式(Adapter Pattern)是一种补救模式,将一个类的接口转换成客户希望的另外一个接口,从而使原本由于接口不兼容而不能一起工作的类可以一起工作。 简述 模式结构 类适配器和对象适配器 优缺点 适用场景 ...

    简述

    适配器模式(Adapter Pattern)是一种补救模式,将一个类的接口转换成客户希望的另外一个接口,从而使原本由于接口不兼容而不能一起工作的类可以一起工作。

    | 版权声明:一去、二三里,未经博主允许不得转载。

    模式结构

    UML 结构图(类适配器):

    Adapter Pattern

    UML 结构图(对象适配器):

    Adapter Pattern

    • Target(目标接口):所期望得到的接口
    • Adaptee(适配者):需要适配的类
    • Adapter(适配器):该模式的核心,具有将 Adaptee 包装为 Target 的职责

    类适配器和对象适配器

    从实现层面上划分,适配器模式分为两种:

    • 类适配器(多继承方式)
    • 对象适配器(对象组合方式)

    那么,实际应用中如何在二者之间进行选择?

    类适配器包含以下特点:

    • 由于 Adapter 直接继承自 Adaptee 类,所以,在 Adapter 类中可以对 Adaptee 类的方法进行重定义。
    • 如果在 Adaptee 中添加了一个抽象方法,那么 Adapter 也要进行相应的改动,这样就带来高耦合。
    • 如果 Adaptee 还有其它子类,而在 Adapter 中想调用 Adaptee 其它子类的方法时,使用类适配器是无法做到的。

    对象适配器包含以下特点:

    • 有的时候,你会发现,去构造一个 Adaptee 类型的对象不是很容易。
    • 当 Adaptee 中添加新的抽象方法时,Adapter 类不需要做任何调整,也能正确的进行动作。
    • 可以使用多态的方式在 Adapter 类中调用 Adaptee 类子类的方法。

    由于对象适配器的耦合度比较低,所以在很多的书中都建议使用对象适配器。在我们实际项目中,也是如此,能使用对象组合的方式,就不使用多继承的方式。

    优缺点

    优点:

    • 可以让任何两个没有关联的类一起运行
    • 提高了类的复用
    • 增加了类的透明度
    • 灵活性好

    缺点:

    • 过多地使用适配器,会让系统非常零乱,不利于整体把控。

    例如,看到调用的是 A 接口,内部却被适配成了 B 接口的实现,系统如果出现太多类似情况,无异于一场灾难。因此,如果不是很必要,可以不使用适配器,而是直接对系统进行重构。

    适用场景

    • 当想使用一个已存在的类,而它的接口不符合需求时。
    • 你想创建一个可复用的类,该类可以与其他不相关的类或不可预见的类协同工作。
    • 你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口,对象适配器可以适配它的父接口。

    案例分析

    莫斯科 - 森林中的首都

    莫斯科、圣彼得堡。。。作为俄罗斯的热门旅游景点,每年都会迎来成百上千万的游客,而中国稳居其第一大客源国。

    要去俄罗斯旅游,手机必不可少,然而,让人头疼的是如何给手机充电!

    世界各国插座标准都不尽相同,甚至同一国家的不同地区也可能不一样。例如,中国一般使用两脚扁型,而俄罗斯使用的是双脚圆形。那么,如果去俄罗斯旅游,就会出现一个问题:我们带去的充电器为两脚扁型,而他们提供的插座为双脚圆形,如何给手机充电呢?总不能为了旅客而随意更改墙上的插座吧,而且俄罗斯人一直都这么使用,并且用的很好。俗话说入乡随俗,那么只能自己想办法解决了。

    Adapter

    其实这个问题的解决方式很简单 - 适配器模式,只需要提供一个电源转化器即可。该转化器的一端符合俄罗斯标准,可以插到俄罗斯的插座上,另一端符合中国标准,可以供我们的手机充电器使用。

    代码实现

    对象适配器

    创建目标接口

    俄罗斯提供的插座:

    // target.h
    #ifndef TARGET_H
    #define TARGET_H
    
    #include <iostream>
    
    // 俄罗斯提供的插座
    class IRussiaSocket
    {
    public:
        // 使用双脚圆形充电(暂不实现)
        virtual void Charge() = 0;
    };
    
    #endif // TARGET_H

    创建适配者

    再来看看我们自带的充电器:

    // adaptee.h
    #ifndef ADAPTEE_H
    #define ADAPTEE_H
    
    #include <iostream>
    
    using namespace std;
    
    // 自带的充电器 - 两脚扁型
    class OwnCharger
    {
    public:
        void ChargeWithFeetFlat() {
            cout << "OwnCharger::ChargeWithFeetFlat" << endl;
        }
    };
    
    #endif // ADAPTEE_H

    创建适配器

    定义一个电源适配器,并使用我们自带的充电器充电:

    // adapter.h
    #ifndef ADAPTER_H
    #define ADAPTER_H
    
    #include "target.h"
    #include "adaptee.h"
    
    #ifndef SAFE_DELETE
    #define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
    #endif
    
    // 电源适配器
    class PowerAdapter : public IRussiaSocket
    {
    public:
        PowerAdapter() : m_pCharger(new OwnCharger()){}
        ~PowerAdapter() {
            SAFE_DELETE(m_pCharger);
        }
        void Charge() {
            //  使用自带的充电器(两脚扁型)充电
            m_pCharger->ChargeWithFeetFlat();
        }
    
    private:
        OwnCharger *m_pCharger;  // 持有需要被适配的接口对象 - 自带的充电器
    };
    
    #endif // ADAPTER_H

    创建客户端

    最终,客户端实现如下:

    // main.cpp
    #include "adapter.h"
    
    int main()
    {
        // 创建适配器
        IRussiaSocket *pAdapter = new PowerAdapter();
    
        // 充电
        pAdapter->Charge();
    
        SAFE_DELETE(pAdapter);
    
        getchar();
    
        return 0;
    }

    输出如下:

    OwnCharger::ChargeWithFeetFlat

    这说明适配器起作用了,现在可以使用两脚扁型插孔充电了。我们并没有改变俄罗斯提供的插座,只提供了一个适配器就能使用中国的标准插口充电。这就是适配器模式的魅力:不改变原有接口,却还能使用新接口的功能。

    类适配器

    Target 和 Adaptee 保持不变,只需要将 Adapter 变为多继承的方式即可:

    #ifndef ADAPTER_H
    #define ADAPTER_H
    
    #include "target.h"
    #include "adaptee.h"
    
    // 电源适配器
    class PowerAdapter : public IRussiaSocket, OwnCharger
    {
    public:
        PowerAdapter() {}
        void Charge() {
            // 使用自带的充电器(两脚扁型)充电
            ChargeWithFeetFlat();
        }
    };
    
    #endif // ADAPTER_H

    除此之外,其他用法和“对象适配器”一致。

    展开全文
  • C++适配器模式

    2019-06-21 11:40:53
    01 用途 两个接口不匹配的类想要交互,直接改接口太繁琐(大工程就体现出来了),就添加第三类(适配器类)来协调两者的关系。 形象理解,假设现在有两个忍者——年轻的忍者和年老...适配器模式分为两类 对象适...

    01 用途

    两个接口不匹配的类想要交互,直接改接口太繁琐(大工程就体现出来了),就添加第三类(适配器类)来协调两者的关系。

    形象理解,假设现在有两个忍者——年轻的忍者年老的忍者,其中年轻的攻击漏洞百出,而年老的则成熟稳健,现在年轻的忍者需要参加考试,所以想打出老年忍者成熟稳健的拳法,适配器就完成了这个转换过程,即用老年忍者来“训练”年轻的忍者。

    02 分类及实现方法

    适配器模式分为两类

    • 对象适配器(更灵活)
      • 继承自需求类(年轻的忍者),内涵一个源类(老年忍者)。
      • 转换方式
        • 继承自需求类,内涵一个源类
        • 拷贝构造函数接受一个源类的引用,并用该引用指向的实例初始化自身内涵的源类
        • 重写目标类中有适配需求的函数
        • 在使用时,用目标类的指针指向该适配器实例,并用该指针调用有适配需求的函数
    • 类适配器
      • 同时继承需求类(年轻的忍者)和源类(老年忍者)
      • 转换方式
        • 同时继承需求类和源类
        • 重写目标类中有适配需求的函数
        • 在使用时,用目标类的指针指向该适配器实例,并用该指针调用有适配需求的函数

    03 Show me the code

    请参考注释阅读,见证训练(适配)结果。

    注意:按照“标准操作”避免内存泄漏,父类的析构函数应该为虚,这里图省事就没有添加析构函数。

    #include <iostream>
    
    
    using namespace std;
    
    
    // 年轻的忍者
    class Ninjia_young {
    public:
    	virtual void fight() {
    		cout << "攻击漏洞百出" << endl;
    	}
    };
    
    
    // 老年忍者
    class Ninjia_old {
    public:
    	virtual void fight() {
    		cout << "成熟稳健的拳法" << endl;
    	}
    };
    
    
    // 对象适配器
    // 继承目标,内涵源
    class Training_object_adaptor :public Ninjia_young{
    private:
    	Ninjia_old old;
    
    public:
    	Training_object_adaptor(const Ninjia_old & outer)
    	: old(outer) {};
    
    	// 重写目标类中的函数
    	void fight() {
    		old.fight();
    	}
    };
    
    
    // 类适配器
    // 继承两者
    class Training_class_adaptor :public Ninjia_young, public Ninjia_old {
    public:
    	// 重写fight方法
    	void fight() {
    		Ninjia_old::fight();
    	}
    };
    
    
    int main() {
    	// 使用对象适配器
    	// Ninjia_young * young = new Training_object_adaptor(Ninjia_old());
    
    	// 使用类适配器
    	Ninjia_young * young = new Training_class_adaptor();
    
    	young->fight();
    
    	delete young;
    
    	young = nullptr;
    }
    
    展开全文
  • c++适配器模式

    2020-02-09 22:05:23
    适配器模式是将两个不同的接口,但是功能相似,适配的一种方法。甚至其中目标接口没有实现,实现类没有接口都是可以的。适配器模式主要强调的是接口和实现不统一,需要将两者兼容的类。

    适配器模式是将两个不同的接口,但是功能相似,适配的一种方法。甚至其中目标接口没有实现,实现类没有接口都是可以的。适配器模式主要强调的是接口和实现不统一,需要将两者兼容的类。

    #include <iostream>
    using namespace std;
    
    //客户程序的接口,可能原本就有,也可能后来提取。这个是适配的目标接口。
    class ICLient {
    public:
        virtual void foo01() = 0;
        virtual void foo02() = 0;
        virtual void foo03() = 0;
    };
    
    //客户自己原有的实现,甚至客户程序没有实现下面的功能。
    class Client01 : public ICLient {
    public:
        void foo01() override {
            cout << "客户程序foo01" << endl;
        }
    
        void foo02() override {
            cout << "客户程序foo02" << endl;
        }
    
        void foo03() override {
            cout << "客户程序foo03" << endl;
        }
    };
    
    //客户原本的调用程序
    void process(ICLient &client) {
        client.foo01();
        client.foo02();
        client.foo03();
    }
    
    //客户程序要在我们的平台上使用,但是我们没有client类
    //我们原有的Mothed类可以实现client功能。
    //我们的Mothed可以没有接口,但是必须有实现。
    class Mothed {
    public:
        void Mothed01() {
            cout << "我们的方法01" << endl;
        }
        void Mothed02() {
            cout << "我们的方法02" << endl;
        }
        void Mothed03() {
            cout << "我们的方法03" << endl;
        }
        void Mothed04() {
            cout << "我们的方法04" << endl;
        }
    };
    
    //现在我们需要新增一个适配作用的类
    class ClientMothed : public ICLient {
    
        Mothed mothed;
    
    public:
        explicit ClientMothed() {}
    
        void foo01() override {
            mothed.Mothed01();
            mothed.Mothed02();
            cout << "方法01 + 方法02 相当于 foo01" << endl;
        }
    
        void foo02() override {
            mothed.Mothed03();
            cout << "方法03 相当于 foo02" << endl;
        }
    
        void foo03() override {
            mothed.Mothed04();
            cout << "方法04 相当于 foo03" << endl;
        }
    };
    
    int main()
    {
        Client01 client01;
        process(client01);
    
        ClientMothed mothed;
        process(mothed);
    
        return 0;
    }
    

    适配模式稳定部分ICLient,易变部分Mothed

    展开全文
  • 当客户在接口中定义了他期望的行为时,我们就可以应用适配器模式,提供一个实现该接口的类,并且扩展已有的类,通过创建子类来实现适配。下面是类适配器的UML图:(2)对象适配器:对象适配器”通过组合除了满足...

    将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
    (1)类适配器:
    当客户在接口中定义了他期望的行为时,我们就可以应用适配器模式,提供一个实现该接口的类,并且扩展已有的类,通过创建子类来实现适配。

    下面是类适配器的UML图:

    (2)对象适配器:

    对象适配器”通过组合除了满足“用户期待接口”还降低了代码间的不良耦合。在工作中推荐使用“对象适配”。下面是对象适配器的UML图:

    (3) 缺省适配器模式:

    缺省适配器模式是一种特殊的适配器模式,但这个适配器是由一个抽象类实现的,并且在抽象类中要实现目标接口中所规定的所有方法,但很多方法的实现都是“平庸”的实现,也就是说,这些方法都是空方法。而具体的子类都要继承此抽象类。

    1、创建PatternAdapter.h

    #ifndef _PATTERNADAPTER_H_
    #define _PATTERNADAPTER_H_
    
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Teacher
    {
    private :
        string s;
    public :
        Teacher(string s)
        {
            this->s=s;
        }
        void teachStart()
        {
            cout<<"start-->"<<s<<endl;
        }
        void teachStop()
        {
            cout<<"stop-->"<<s<<endl;
        }
    };
    
    class Print
    {
        virtual void printStart()=0;
        virtual void printStop()=0;
    };
    
    class PrintTeacher:private Teacher,private Print
    {
    public :
        PrintTeacher(string s):Teacher(s){}
        virtual void printStart()
        {
            Teacher::teachStart();
        }
    
        virtual void printStop()
        {
            Teacher::teachStop();
        }
    };
    
    #endif

    2、创建Client.h

    #include <iostream>  
    
    #include "Iterator.h"
    #include "PatternAdapter.h"
    #include <string>
    
    using namespace std;  
    
    
    int main()  
    {  
        string s("zhongguorenmin");
        PrintTeacher * pt=new PrintTeacher(s);
    
        pt->printStart();
        pt->printStop();
    
        delete pt;
    
        system("pause");  
        return 0;  
    }  
    展开全文
  • 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。 这种类型的设计模式属于结构型模式。 意图: 将一个类的接口转换成为客户希望的另一个接口。 适配器模式使得原本由于接口不兼容而不能一起工作的...
  • c++适配器模式adapter

    2020-10-27 09:00:50
    Adapter模式也叫适配器模式,是构造型模式之一,通过Adapter模式可以改变已有类(或外部类)的接口形式。 角色和职责** 适用于: 是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起...
  • 适配器模式解决的问题: 将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 源码 #include <iostream> // 目标类,就是用户最终需要...
  • C++适配器模式示例

    2019-09-20 00:48:12
    #include <iostream> #include <stdarg.h> using namespace std; class ILogger { public: virtual void WriteLog(string format, ...) = 0; }; class LocalLogger: public ILogger ...public:...
  • ,归并排序算法的函数参数量为4个,简单排序算法的参数量为2个,接口不兼容,因此采用适配器模式,适配接口。 Sort.h内增加: class MergeSort :public Sort { public: virtual void sortSeq(int a[], int n); ...
  • #pragma once class Duck { public: Duck(); virtual void quack() = 0; virtual void fly() = 0; };

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,059
精华内容 7,623
关键字:

c++适配器模式

c++ 订阅