大话设计模式 —— 第十七章《适配器模式》C++ 代码实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/89408958

目录

定义

优点 

缺点

使用场景

在我们平时的开发过程中,碰到要在两个完全没有关系的类之间进行交互,第一个解决方案是修改各自类的接口,但是如果无法修改源代码或者其他原因导致无法更改接口,此时怎么办?这种情况我们往往会使用一个 Adapter ,在这两个接口之间创建一个粘合剂接口,将原本无法协作的类进行兼容,而且不用修改原来两个模块的代码,符合开闭原则。


定义


适配器模式(也叫变压器模式)是一种结构型设计模式。该模式的主要功能是将一个类与另一个类的接口匹配起来,使得这两个类的接口都可以使用同一种接口被调用。先来看一下它的定义:

  • 把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。

适配器模式的形式分为:类的适配器模式和对象的适配器模式。本质区别是类适配器是类间的继承,而对象适配器是对象的组合关系。 不过这里讲述的是 对象的适配器模式。

适配器模式有以下三种角色:

  • Target 目标角色,该角色定义把其他类转换为何种接口,也就是我们的期望得到的接口。

  • Adaptee源角色, 现在需要适配的接口

  • Adapter适配器角色,适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要新建立的,它的职责非常简单:把Adaptee 类 通过继承或者类关联的方法转换为 Target类

下面用C++ 代码实现大话数据模式本章代码:

class Player // Target,定义用户实际需要的接口。
{
protected:
	string m_name;
public:
	virtual ~Player() = default;
	explicit Player(string name) :m_name(name) {}
	virtual void Attack() = 0;  // 攻击
	virtual void Defense() = 0;  // 防守
};

class Forwads :public Player
{
public:
	explicit Forwads(string name) :Player(name) {}
	void Attack()override
	{
		cout << "前锋:" << m_name << "进攻!" << endl;
	}
	void Defense()override
	{
		cout << "前锋:" << m_name << "防守!" << endl;
	}
};


class Guards :public Player
{
public:
	explicit Guards(string name) :Player(name) {}
	void Attack()override
	{
		cout << "后卫:" << m_name << "进攻!" << endl;
	}
	void Defense()override
	{
		cout << "后卫:" << m_name << "防守!" << endl;
	}
};

class ForeignCenter // Adaptee,此处为外籍中锋,它的接口和Target的接口不一样,是现在需要适配的接口
{
private:
	string m_name;
public:
	void setName(string name) { m_name = name; }
	void YaoMingAttack()
	{
		cout << "外籍中锋:" << m_name << "进攻!" << endl;
	}
	void YaoMingDefense()
	{
		cout << "外籍中锋:" << m_name << "防守!" << endl;
	}

};

class Translator : public Player  // Adapter , 通过在内部包装一个 Adaptee 对象,把 Adaptee 转换成 Target 
{
private:
	ForeignCenter myForeignCenter;
public:
	explicit Translator(string name) :Player(name) 
	{
		myForeignCenter.setName(name);
	}
	void Attack()override
	{
		myForeignCenter.YaoMingAttack();
	}
	void Defense()override
	{
		myForeignCenter.YaoMingDefense();
	}
};
int main()
{
	Player *b = new Forwads("巴蒂尔");
	b->Attack();

	Player *m = new Guards("麦克格雷迪");
	m->Attack();

	Player *ym = new Translator("姚明");
	ym->Attack();
	ym->Defense();

	delete b; 
	delete m;
	delete ym;
	b = nullptr;
	m = nullptr;
	ym = nullptr;
	system("pause");
	return 0;
}

运行后截图:



 


优点 


更好的复用性 

  • 系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。


透明、简单 

  • 客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单 ,也更直接


更好的扩展性 

  • 在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。


解耦性 

  • 通过引入适配器,可以复用现有的类,而不需要修改源代码, 将目标类和被适配者解耦, 解决了接口和复用环境不一致的情况


符合开放-关闭原则 

  • 当添加一个实现Adaptee接口的新类时,不必修改Adapter,Adapter就能对这个新类的实例进行适配。

灵活性非常好

  •    某一天,突然不想要适配器,没问题,删除掉这个适配器就可以了,其他的代码都不用修改,基本上就类似一个灵活的构件,想用就用,不想就卸载。

缺点


  • 过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

使用场景


  • 一个程序想使用已经存在的类,但该类所实现的接口和当前程序所使用的接口不一致时,就应该考虑用适配器模式。
  • 两个类的职责相同或相似,但是具有不同的接口时要使用它;
  • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大联系的一些类,包括一些可能在将来引进的类一起工作; 
  • 双方都不太容易修改:第三方组件组件的接口,与系统接口不符 

注意:要在双方都不太容易修改的时候再使用适配器模式适配,而不是一有不同是就使用它。
 

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/89408958