[设计模式C++go]结构型模式:适配器模式

Posted 凌星An

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[设计模式C++go]结构型模式:适配器模式相关的知识,希望对你有一定的参考价值。

适配器模式

介绍

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。
这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

其定义:
Convert the interface of a class into another interface clients
expect.Adapter lets classes work together that couldn't otherwise because ofincompatible interfaces.(将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。)

比如:你现在遇到一个外国人,但是你不懂外语,那么怎么交流呢?可以使用手机即时翻译软件,让你们能顺利沟通,这就体现了适配器模式的原理。

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

主要解决: 在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。

何时使用:
1、系统需要使用现有的类,而此类的接口不符合系统的需要。
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

如何解决: 继承或依赖(推荐)。

关键代码: 适配器继承或依赖已有的对象,实现想要的目标接口。

类图

代码实现

我们现在处于A公司,A公司的员工员工信息是同一个类处理的(姓名、电话、身份证、职位、公司电话);A公司最近收购B公司,B公司的员工信息是分成两个类处理的,基本信息(姓名,电话,身份证),公司信息(身份证,职位,公司电话) ;公司要求统一处理A,B公司员工信息。 用代码实现此过程

C++

/A公司员工信息处理///
class staffInfo
	public:
		staffInfo(std::string name="", std::string phone="", std::string idCard="", std::string jobPosition="", std::string OfficePhone="")
			_name = name;
			_phone = phone;
			_idCard = idCard;
			_jobPosition = jobPosition;
			_OfficePhone = OfficePhone;
		

		void GetStaffInfo()
			std::cout << "name:" << _name << std::endl;
			std::cout << "phone:" << _phone << std::endl;
			std::cout << "idCard:" << _idCard << std::endl;
			std::cout << "jobPosition:" << _jobPosition << std::endl;
			std::cout << "OfficePhone:" << _OfficePhone << std::endl;
		
		std::string GetName()
			return _name;
		
		std::string GetPhone()
			return _phone;
		
		std::string GetIDCard()
			return _idCard;
		
		std::string GetJobPosition()
			return _jobPosition;
		
		std::string GetOfficePhone()
			return _OfficePhone;
		
	private:
		//基本信息
		std::string _name;
		std::string _phone;
		std::string _idCard;
		//公司信息
		std::string _jobPosition;
		std::string _OfficePhone;
	;

	class Target
	public:
		virtual void GetStaffInfo() = 0;
		virtual void AddStaffInfo(staffInfo staff) = 0;
	;

	class StaffInfos:public Target
	public:
		void AddStaffInfo(staffInfo staff)
			_map[staff.GetIDCard()] = staff;
		
		void GetStaffInfo()
			auto e = _map.begin();
			while (e != _map.end())
				e->second.GetStaffInfo();
				e++;
			
		
	private:
		std::unordered_map<std::string, staffInfo> _map;
	;

B公司员工信息//
namespace B
	class staffBaseInfo
	public:
		staffBaseInfo(std::string name="", std::string phone="", std::string idCard="")
			_name = name;
			_phone = phone;
			_idCard = idCard;
		
		void GetStaffInfo()
			std::cout << "name:" << _name << std::endl;
			std::cout << "phone:" << _phone << std::endl;
			std::cout << "idCard:" << _idCard << std::endl;
		
		std::string GetIDCard()
			return _idCard;
		
	private:
		//基本信息
		std::string _name;
		std::string _phone;
		std::string _idCard;
	;

	class staffCompanyInfo
	public:
		staffCompanyInfo(std::string idCard="", std::string jobPosition="", std::string OfficePhone="")
		

			_idCard = idCard;
			_jobPosition = jobPosition;
			_OfficePhone = OfficePhone;
		
		std::string GetIDCard()
			return _idCard;
		
		void GetStaffInfo()
			std::cout << "jobPosition:" << _jobPosition << std::endl;
			std::cout << "OfficePhone:" << _OfficePhone << std::endl;
		
	private:
		std::string _idCard;
		//公司信息
		std::string _jobPosition;
		std::string _OfficePhone;
	;
	class StaffBaseInfos
	public:
		void AddStaffInfo(staffBaseInfo staff)
			_map[staff.GetIDCard()] = staff;
		
		void GetStaffInfo()
			auto e = _map.begin();
			while (e != _map.end())
				e->second.GetStaffInfo();
				e++;
			
		
	private:
		std::unordered_map<std::string, staffBaseInfo> _map;
	;
	class StaffCompanyInfos
	public:
		void AddStaffInfo(staffCompanyInfo staff)
			_map[staff.GetIDCard()] = staff;
		
		void GetStaffInfo()
			auto e = _map.begin();
			while(e != _map.end())
				e->second.GetStaffInfo();
				e++;
			
		
	private:
		std::unordered_map<std::string, staffCompanyInfo> _map;
	;



适配类///
class Apdater :public Target
public:
	Apdater(B::StaffBaseInfos SBI, B::StaffCompanyInfos SCI)
		_SBI = SBI;
		_SCI = SCI;
	
	void AddStaffInfo(staffInfo staff)
		B::staffBaseInfo   tmpBase(staff.GetName(), staff.GetPhone(), staff.GetIDCard());
		B::staffCompanyInfo tmpCompany(staff.GetIDCard(), staff.GetJobPosition(), staff.GetOfficePhone());
		_SBI.AddStaffInfo(tmpBase);
		_SCI.AddStaffInfo(tmpCompany);
	
	void GetStaffInfo()
		_SBI.GetStaffInfo();
		_SCI.GetStaffInfo();
	
private:
	B::StaffBaseInfos _SBI;
	B::StaffCompanyInfos _SCI;
;

测试

A公司处理/
	staffInfo   Astaff1("小明", "123", "1", "A_enginer", "000");
	StaffInfos ASS;
	ASS.AddStaffInfo(Astaff1);
B公司处理///
	B::staffBaseInfo BstaffB1("小红","124", "2");
	B::staffCompanyInfo BstaffC1("2", "B_enginer", "009");
	B::StaffBaseInfos  SBIS;
	SBIS.AddStaffInfo(BstaffB1);
	B::StaffCompanyInfos  BSCS;
	BSCS.AddStaffInfo(BstaffC1);
//
   //我们仅需要改变这一处代码就ok了
	//Target* t =&ASS;
	Target* t = new Apdater(SBIS, BSCS); 

	t->GetStaffInfo();

go

package Adpater

import "fmt"

/A公司/
type StaffInfo struct 
	//基本信息
	_name   string
	_phone  string
	_idCard string
	//公司信息
	_jobPosition string
	_officePhone string


func (s *StaffInfo) SetStaffInfo(name, phone, idCard, jobPosition, officePhone string) 
	s._name, s._phone, s._idCard, s._jobPosition, s._officePhone = name, phone, idCard, jobPosition, officePhone

func (s *StaffInfo) GetStaffInfo() 
	fmt.Println("name:", s._name)
	fmt.Println("phone:", s._phone)
	fmt.Println("IDCard", s._idCard)
	fmt.Println("JobPosition", s._jobPosition)
	fmt.Println("OfficePhone", s._officePhone)

func (s *StaffInfo) GetName() string 
	return s._name

func (s *StaffInfo) GetPhone() string 
	return s._phone

func (s *StaffInfo) GetIDCard() string 
	return s._idCard

func (s *StaffInfo) GetJobPosition() string 
	return s._jobPosition

func (s *StaffInfo) GetOfficePhone() string 
	return s._officePhone


type Target interface 
	GetStaffInfo()
	AddStaffInfo(staff StaffInfo)


type StaffInfos struct 
	smap map[string]StaffInfo


func (s *StaffInfos) GetStaffInfo() 
	for _, v := range s.smap 
		v.GetStaffInfo()
	


func (s *StaffInfos) AddStaffInfo(staff StaffInfo) 
	if s.smap == nil 
		s.smap = make(map[string]StaffInfo)
	
	s.smap[staff.GetName()] = staff




///B公司///
type StaffBaseInfo struct 
	_name   string
	_phone  string
	_idCard string


func (s *StaffBaseInfo) GetStaffInfo() 
	fmt.Println("name:", s._name)
	fmt.Println("phone:", s._phone)
	fmt.Println("IDCard", s._idCard)


func (s *StaffBaseInfo) GetIDcard() string 
	return s._idCard


func (s *StaffBaseInfo) SetStaffInfo(name, phone, idCard string) 
	s._name, s._phone, s._idCard = name, phone, idCard


type StaffCompanyInfo struct 
	_idCard      string
	_jobPosition string
	_officePhone string


func (s *StaffCompanyInfo) SetStaffInfo(idCard, jobPosition, officePhone string) 
	s._idCard, s._jobPosition, s._officePhone = idCard, jobPosition, officePhone


func (s *StaffCompanyInfo) GetStaffInfo() 
	fmt.Println("JobPosition", s._jobPosition)
	fmt.Println("OfficePhone", s._officePhone)


func (s *StaffCompanyInfo) GetIDcard() string 
	return s._idCard


type StaffBaseInfos struct 
	smap map[string]StaffBaseInfo


func (s *StaffBaseInfos) AddStaffInfo(staff StaffBaseInfo) 
	if s.smap == nil 
		s.smap = make(map[string]StaffBaseInfo)
	
	s.smap[staff.GetIDcard()] = staff


func (s *StaffBaseInfos) GetStaffInfo() 
	for _, v := range s.smap 
		v.GetStaffInfo()
	


type StaffCompanyInfos struct 
	smap map[string]StaffCompanyInfo


func (s *StaffCompanyInfos) AddStaffInfo(staff StaffCompanyInfo) 
	if s.smap == nil 
		s.smap = make(map[string]StaffCompanyInfo)
	
	s.smap[staff.GetIDcard()] = staff


func (s *StaffCompanyInfos) GetStaffInfo() 
	for _, v := range s.smap 
		v.GetStaffInfo()
	


/

//Apdater类///
type Apdater struct 
	sc StaffCompanyInfos
	sb StaffBaseInfos


func (s *Apdater) AddStaffInfo(staff StaffInfo) 
	s.sb.AddStaffInfo(StaffBaseInfostaff.GetName(), staff.GetPhone(), staff.GetIDCard())
	s.sc.AddStaffInfo(StaffCompanyInfostaff.GetIDCard(), staff.GetJobPosition(), staff.GetOfficePhone())


func (s *Apdater) GetStaffInfo() 
	s.sb.GetStaffInfo()
	s.sc.GetStaffInfo()

测试

//A公司
	staffA := Adpater.StaffInfo
	staffA.SetStaffInfo("小明", "123", "1", "A_enginer", "000")

	staffAs := Adpater.StaffInfos
	staffAs.AddStaffInfo(staffA)
	///B/
	staffBbase := Adpater.StaffBaseInfo
	staffBbase.SetStaffInfo("小红", "124", "2")
	staffBbases := Adpater.StaffBaseInfos
	staffBbases.AddStaffInfo(staffBbase)

	staffBCompany := Adpater.StaffCompanyInfo
	staffBCompany.SetStaffInfo("2", "B_enginer", "009")
	staffBCompanys := Adpater.StaffCompanyInfos
	staffBCompanys.AddStaffInfo(staffBCompany)

	/使用
	//var tar Adpater.Target = &staffAs
	var tar Adpater.Target = &Adpater.ApdaterstaffBCompanys, staffBbases
	tar.GetStaffInfo()

优缺点

优点:

  • 更好的复用性
    适配器模式可以让两个没有任何关系的类在一起运行,只要适配器这个角色能够搞定他们就成
  • 增加了类的透明性
    对高层次模块是透明的,也是它不需要关心的。
  • 提高了类的复用度
    当然了,源角色在原有的系统中还是可以正常使用,而在目标角色中也可以充当新的演员。
  • 灵活性非常好
    某一天,突然不想要适配器,没问题,删除掉这个适配器就可以了,其他的代码都不用修改,基本上就类似一个灵活的构件,想用就用,不想就卸载。

缺点:

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

注:

如果能事先预防接口不同的问题,不匹配问题就不会发生;在有小的接口不统一问题发生时,及时重构,问题不至于扩大;只有碰到无法改变原有设计和代码的情况时,才考虑适配。事后控制不如事中控制,事中控制不如事前控制。(《大话设计模式》)

以上是关于[设计模式C++go]结构型模式:适配器模式的主要内容,如果未能解决你的问题,请参考以下文章

使用Go实现GoF的23种设计模式

[设计模式C++go]结构型模式:代理模式

[设计模式C++go]结构型模式:代理模式

[设计模式C++go]结构型模式:代理模式

[设计模式C++go]结构型模式:桥接模式

[设计模式C++go]结构型模式:桥接模式