5.适配器模式

目录

一、适用场景

1.1 现实场景举例

  1. 已经存在的接口如下
cpp 复制代码
class ITarget
{
public:
	void run();
};
  1. 如果要再加一个fly()方法,还要求不能违反开放封闭原则要如何处理

1.2 修改

  1. ITarget接口中添加void fly();方法
  2. 违反了对修改进行封闭的原则,这样做了之后,以前实现该接口的类都要实现该方法。
  3. 此时,就要用到适配器模式

二、使用环境

  1. 想使用一个已经存在的类,但他的接口不符合需求
  2. 将一个类的接口转换成客户希望的另外一个接口,使得原来由于接口不兼容而不能在一起工作的那些类可以一起工作。

三、适配器模式详解

  • 适配器模式有以下四种角色
    • 目标(target):定义客户端使用的与特定领域相关的接口
    • 被适配者(adaptee):定义了一个已经存在的接口,这个接口需要匹配。
    • 适配者(adapter):对Adaptee的接口与target的接口进行适配
    • 客户端(client):与符合target接口的对象协同

四、适配器模式分类

  • 类的适配器模式(采用继承实现)
    • Target:就是最终的包括run()fly()的接口
    • Adaptee: 等待着被转换(完成fly()的类)
    • Adapter: 要被转换的结果对象,只要继承Adaptee接口并实现Target即可
  • 对象适配器(采用对象组合方式实现,推荐,也满足合成复用原则)
  • 类的适配器结构基本相同
  • 差异在于Adapter和Adaptee的关系上
    • 类的适配器模式采用继承关系
    • 对象适配器采用关联关系,关联关系的箭头端的类(Adaptee)会有一个实例进入箭头末端的类(Adapter)中。

五、应该用哪种适配器

  • 类适配器采用"多继承"的实现方式,带来了不良的高耦合
  • 对象适配器采用"对象组合"的方式,更符合松耦合精神
  • 类适配器无法面对多个被适配对象
  • 推荐使用对象适配器

六、实现步骤

两种适配器的步骤相同

  1. 确定目标接口
  2. 确定被适配者
  3. 创建适配器(继承自被适配者/拥有被适配者的对象,实现目标接口)

七、代码实现

7.1 确定目标接口

cpp 复制代码
class ITarget
{
public:
	virtual void run() = 0;
	virtual void fly() = 0;
};

7.2 确定被适配者

cpp 复制代码
class Deer
{
public:
	void run()
	{
		std::cout << "I can run." << std::endl;
	}
};

7.3 创建适配器

7.3.1 类适配器

cpp 复制代码
#include <iostream>

class ITarget
{
public:
	virtual void run() = 0;
	virtual void fly() = 0;

	virtual ~ITarget() = default;
};

class Deer
{
public:
	void run()
	{
		std::cout << "I can run." << std::endl;
	}
};

//继承原有的Deer,并实现ITarget
class classAdapter : public Deer, public ITarget
{
public:
	void fly() override
	{
		std::cout << "I can fly" << std::endl;
	}

	//显式的告诉编译器使用Deer中的run来实现ITarget中的run
	void run() override
	{
		Deer::run();
	}
};

int main()
{
	ITarget* target = new classAdapter();
	target->fly();
	target->run();

	delete(target);
	return 0;
}

7.3.2 对象适配器

cpp 复制代码
#include <iostream>

class ITarget
{
public:
	virtual void run() = 0;
	virtual void fly() = 0;

    virtual ~ITarget() = default;
};

class Deer
{
public:
	void run()
	{
		std::cout << "I can run." << std::endl;
	}
};

//继承原有的Deer,并实现ITarget
class classAdapter: public ITarget
{
private:
	Deer* m_deer; //有一个Deer的实例,在构造函数中被赋值

public:
	classAdapter(Deer* deer)
	{
		m_deer = deer;
	}

	void fly() override
	{
		std::cout << "I can fly" << std::endl;
	}

	void run() override
	{
		m_deer->run();
	}
};

int main()
{
	Deer d;
	ITarget* target = new classAdapter(&d);
	target->fly();
	target->run();
   	
   	delete(target);
	return 0;
}
相关推荐
qq_2975746712 小时前
设计模式系列文章(基础篇第19篇):中介者模式——封装交互关系,解耦网状依赖
设计模式·交互·中介者模式
AI大法师13 小时前
老牌媒体怎么从“出版物更新”走到“品牌系统升级”
大数据·人工智能·设计模式·新媒体运营
野生技术架构师13 小时前
Java 23 种设计模式:从踩坑到精通 —— 开篇及系列介绍
java·开发语言·设计模式
艾利克斯冰13 小时前
Java设计模式-创建型模式(更新完成)
设计模式
王_teacher14 小时前
23种设计模式之工厂模式
设计模式·软件工程·简单工厂模式·工厂方法模式·抽象工厂模式
geovindu14 小时前
python:Coroutines Pattern
开发语言·python·设计模式·协程模式
sycmancia16 小时前
Qt——模型视图设计模式
设计模式
玖玥拾1 天前
C/C++ 基础笔记(十一)类的进阶
c语言·c++·设计模式·
geovindu1 天前
go: Broadcast Pattern
开发语言·后端·设计模式·golang·广播模式
我爱cope1 天前
【Agent智能体23 | 规划-规划工作流】
人工智能·设计模式·语言模型·职场和发展