设计模式之适配器模式(Adapter)C++实现

适配器模式通过转换接口使不兼容的类能够一起工作。本文详细介绍了适配器模式的概念,适用场景,并提供了C++的类适配器和对象适配器的代码示例,结合姚明在NBA打球的例子帮助理解其工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

适配器模式:是将一个类的接口转换成客户想希望的另外一个接口。Adapter模式使得原本由于接口不兼容的而不能一起工作的那些类可以一起工作。

简单的来说是配置是解决主要一类问题:我们需要的东西就在面前,但是却不能用,短时间又无法改造它,于是我们就想办法适配它。比如说我们购买笔记本等电子产品时,经常会带一个电源适配器,这是因为我们家用点的电压是220V的,而一般的笔记本工作电压在16V到22V之间,因此为了使我们的笔记本能够正常工作,不至于直接介入家用电烧坏电脑,我们 就需要一个电源适配器,将家用电压220转换成笔记本的工作电压。这就是适配器的作用。同理适配器模式就是我们希望使用一个类的接口,但是这个接口与当前系统不兼容,我们就需要一个适配器去对这个接口做转换,是它适合当前系统。

软件开发中,系统的数据和行为都正确,但接口不符时我们有考虑使用适配器,目的是使控制范围之外的一个原有对象与某个接口适配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况,比如我们需要对早期代码复用一些功能等应用上很有实际价值。

GOF介绍的适配器模式分类类适配器和对象适配器,由于除C++之外其他语言不支持多重继承,因此只有C++可以实现类适配器。

通用类适配器的UML图(类适配器和对象适配器)

Target:定义Client使用的于特定领域相关的接口

Adaptee:定义一个已经存在的接口,这个接口需要适配

Adapter:对Adaptee和Target的接口进行适配。


何时使用适配器模式:

1、你想使用一个已经存在的类,而它的接口不符合你的要求

2、你想创建一个可以复用的类,该类可以与其他不相关或者不可预见的类(即那些接口可能不兼容的类)协同工作

3、(仅适用对象适配器)你想使用一些已经存在的类,但是不可能对每一个都进行子类化以匹配它们的接口,对象试用期可以适配它的父类接口。

下面提出通用型的对象适配器和类适配器代码:

Adapter.h

class Target
{
public:
	~Target(){};
	virtual void Request();
};

class Adaptee
{
public:
	~Adaptee(){};
	void SpecialRequest();
};


/*
//类适配器
class Adapter : public Target, private Adaptee
{
public:
	~Adapter();
	virtual void Request();
};

*/

//对象适配器
class Adapter : public Target
{
public:
	Adapter();
	~Adapter(){delete pAdaptee};
	virtual void Request();
private:
	Adaptee* pAdaptee;
};

Adapter.cpp

#include"Adapter.h"
#include <iostream>

using namespace std;
void Target::Request()
{
	cout << "客户的一般请求\n";
}

void Adaptee::SpecialRequest()
{
	cout << "客户实际想调用的接口\n";
}

/*
类适配器的实现
void Adapter::Request()
{
	SpecialRequest();
}
*/

Adapter::Adapter()
{
	pAdaptee = new Adaptee();
}

void Adapter::Request()
{
	pAdaptee->SpecialRequest();
}

客户端代码:

#include"Adapter.h"

int main()
{
	Adapter* pAdapter = new Adapter();
	pAdapter->Request();
	return 0;
}


为了更好的理解适配器模式,我取了大话设计模式书中的有关适配器的例子。假设姚明刚去NBA打球,那时候姚明的英语并不好,完全不能听懂教练的战术,教练让姚明去内线攻击,或者拉到三分线往里一部中投,逼迫对手的防线向外,是的麦迪能够更好的往内线突破。那么姚明是这样执行战术的:

Player.h

#include <iostream>
class Player
{
protected:
	std::string m_name;
public:
	virtual void Attack() = 0;
	virtual void Defend() = 0;
	virtual ~Player(){};
	Player(const char * name){ m_name = name; }
};

class Forwards :public Player
{
public:
	Forwards(const char* name) :Player(name){};
	virtual ~Forwards(){};
	virtual void Attack();
	virtual void Defend();
};

class Center :public Player
{
public:
	Center(const char* name) :Player(name){};
	virtual ~Center(){};
	virtual void Attack();
	virtual void Defend();
};

class Guards :public Player
{
public:
	Guards(const char* name) :Player(name){};
	virtual ~Guards(){};
	virtual void Attack();
	virtual void Defend();
};


Player.cpp

#include "Adapter.h"

void Forwards::Attack()
{
	std::cout <<  "Forwards " << m_name.c_str() << " Attack\n";
}

void Forwards::Defend()
{
	std::cout << "Forwards " << m_name.c_str() << "Defend\n";
}

void Center::Attack()
{
	std::cout << "Center " << m_name.c_str() << " Attack\n";
}

void Center::Defend()
{
	std::cout << "Center " << m_name.c_str() << " Defend\n";
}

void Guards::Attack()
{
	std::cout << "Guards " << m_name.c_str() << " Attack\n";
}

void Guards::Defend()
{
	std::cout << "Guards " << m_name.c_str() << " Defend\n";
}


教练的战术:

#include "Adapter.h"

int main()
{
	Player* bt = new Guards("batier");
	bt->Attack();
	
	Player* md = new Forwards("MgRadi");
	md->Attack();

	Center* ym = new Center("yaoming");
	ym->Attack();
	ym->Defend();

	delete bt;
	delete md;
	delete ym;
	return 0;
}



教练的战术中,教练让姚明先攻击如果投篮不中马上防守抢进攻篮板然后执行二次进攻,然而姚明不懂英语根本不知道教练在说什么,姚明的接到球后没有投篮而是把球传给了麦迪,24秒进攻违例,丢了球权,范甘迪大为恼火,总结该次进攻的问题最重要的是姚明听不懂英语,不清楚教练在说什么,以至于根本就没执行教练布置的战术。那怎么办呢?于是乎,教练想到给姚明配一个翻译员,该翻译员负维护了一个需要翻译的球员的引用,然后教练布置战术时教练先跟翻译说,然后翻译再告诉姚明,姚明就知道怎么做了。代码如下:

player.h

#include <iostream>
class Player
{
protected:
	std::string m_name;
public:
	virtual void Attack() = 0;
	virtual void Defend() = 0;
	virtual ~Player(){};
	Player(const char * name){ m_name = name; }
};

class Forwards :public Player
{
public:
	Forwards(const char* name) :Player(name){};
	virtual ~Forwards(){};
	virtual void Attack();
	virtual void Defend();
};

class Center :public Player
{
public:
	Center(const char* name) :Player(name){};
	virtual ~Center(){};
	virtual void Attack();
	virtual void Defend();
};

class Guards :public Player
{
public:
	Guards(const char* name) :Player(name){};
	virtual ~Guards(){};
	virtual void Attack();
	virtual void Defend();
};

//外籍中锋
class FroeignCenter
{
public:
	FroeignCenter(const char* name) { m_name = name; };
	void Attack();
	void Defend();
private:
	std::string m_name;
};

class Translater : public Player
{
private:
	FroeignCenter* pForCenter;
public:
	Translater(const char *);
	void Attack();
	void Defend();

};

Player.cpp

#include "Adapter.h"

void Forwards::Attack()
{
	std::cout <<  "Forwards " << m_name.c_str() << " Attack\n";
}

void Forwards::Defend()
{
	std::cout << "Forwards " << m_name.c_str() << "Defend\n";
}

void Center::Attack()
{
	std::cout << "Center " << m_name.c_str() << " Attack\n";
}

void Center::Defend()
{
	std::cout << "Center " << m_name.c_str() << " Defend\n";
}

void Guards::Attack()
{
	std::cout << "Guards " << m_name.c_str() << " Attack\n";
}

void Guards::Defend()
{
	std::cout << "Guards " << m_name.c_str() << " Defend\n";
}

void FroeignCenter::Attack()
{
	std::cout << "外籍中锋:" << m_name.c_str() << "进攻\n";
}

void FroeignCenter::Defend()
{
	std::cout << "外籍中锋:" << m_name.c_str() << "防守\n";
}

Translater::Translater(const char* name) :Player(name)
{
	pForCenter = new FroeignCenter(name);
}

void Translater::Attack()
{
	pForCenter->Attack();
}

void Translater::Defend()
{
	pForCenter->Defend();
}

教练布置战术:

#include "Adapter.h"

int main()
{
	Player* bt = new Guards("batier");
	bt->Attack();
	
	Player* md = new Forwards("MgRadi");
	md->Attack();

	Player* ym = new Translater("yaoming");
	ym->Attack();
	ym->Defend();

	delete bt;
	delete md;
	delete ym;
	return 0;
}

姚明就可以看懂教练对自己说什么了。

教练想要告诉姚明该怎么做的已经翻译成中文了,于是姚明马上能理解要怎么打球,这个赛季姚明取得了突破性的提高,入选了全明星,力压火花成为NBA第一中锋

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值