第8章 适配器模式
适配器(Adaptor)模式PPT教学课件

2020/12/10
7
类适配器简单例子
public interface Print { public abstract void printWeak(); public abstract void printStrong();
} }
2020/12/10
9
对象适配器
Client
RequiredClass ______________ requiredMethod()
ExistingClass __________ usefulMethod()
} ============================ public class Main {
public static void main(String[] args) { Print p = new PrintBanner("Hello"); p.printWeak(); p.printStrong();
2020/12/10
4
Adapter模式
Struct
class adapter
object adapter
2020/12/10
5
例子
《interface》
RocketSim getMass():double getThrust():double setSimTime(t:double)
PhysicalRocket
} -------------------------public class Banner {
适配器模式和组合模式的比较

适配器模式和组合模式的比较适配器模式和组合模式都是常用的设计模式,它们在实际开发中经常被用到。
虽然这两种模式看起来很像,但它们的作用和实现方式有很大的区别。
在本文中,我们将介绍适配器模式和组合模式的比较。
一、适配器模式适配器模式是一种结构性设计模式,它能够将不兼容的接口转换成另一种接口,使得不同类之间能够相互协作。
适配器模式的核心思想是将一个类的接口,转换成客户端所期望的另一种接口,从而使得原本不兼容的类能够协同工作。
适配器模式的实现方式通常有两种:类适配器和对象适配器。
其中,类适配器使用继承机制对源接口进行扩展,而对象适配器则是使用组合机制来实现接口转换。
适配器模式的应用场景比较广泛,例如在使用第三方库时,可能会遇到接口不兼容的情况,此时就可以使用适配器模式来解决这个问题。
二、组合模式组合模式是一种结构性设计模式,它将对象组合成树形结构,使得用户无需区分单个对象和组合对象,从而可以统一地处理所有对象。
组合模式的核心思想是将对象组合成树形结构,从而将复杂的对象模型简化为单一的对象结构。
组合模式的实现方式通常有两种:透明组合模式和安全组合模式。
其中,透明组合模式是将叶子对象和组合对象都看做一种对象,从而对外具体透明,而安全组合模式则是将叶子对象和组合对象分开处理,从而增强了类型安全。
组合模式的应用场景比较广泛,例如在操作文件系统时,可能会遇到需要同时操作文件和目录的情况,此时就可以使用组合模式来解决这个问题。
三、适配器模式和组合模式的比较适配器模式和组合模式都是常用的设计模式,它们在实际开发中经常被用到。
虽然这两种模式看起来很像,但它们的作用和实现方式有很大的区别。
首先,适配器模式的主要作用是将不兼容的接口转换成另一种接口,从而使得不同类之间能够相互协作。
而组合模式的主要作用是将对象组合成树形结构,从而可以统一地处理所有对象。
其次,适配器模式通常使用继承或组合机制来实现接口转换,而组合模式则是使用组合机制来实现对象的组合。
适配器模式实现方式详解

适配器模式实现方式详解适配器模式是一种非常重要的设计模式,主要用于解决不兼容的问题。
适配器模式的核心思想是将一个类的接口转换成另一个客户希望的接口。
在本文中,我们将详细介绍适配器模式的实现方式,包括类适配器、对象适配器和接口适配器。
一、类适配器类适配器是最常用的适配器实现方式之一。
它使用多重继承的方式对目标接口和源接口进行适配。
在类适配器中,适配器类同时继承了目标接口和源接口。
适配器类从源接口继承了需要适配的方法,并在实现目标接口时,将这些方法进行适当的转换。
下面是一个简单的类适配器实现示例:```c++// 源接口class Adaptee {public:virtual void adapteeMethod() {// TODO: 实现需要适配的方法}};// 目标接口class Target {public:virtual void targetMethod() = 0;};// 适配器类class Adapter : public Target, private Adaptee { public:virtual void targetMethod() {adapteeMethod(); // 调用需要适配的方法 // TODO: 实现对目标接口的转换}};上述代码中,适配器类同时继承了目标接口(Target)和源接口(Adaptee),并在实现目标接口时将需要适配的方法适当地转换了一下。
二、对象适配器对象适配器也是一种常用的适配器实现方式。
与类适配器不同的是,对象适配器使用组合的方式进行适配,而不是继承。
在对象适配器中,适配器类持有一个源接口的实例,并使用该实例将目标接口适配成源接口。
下面是一个简单的对象适配器实现示例:```c++// 源接口class Adaptee {public:virtual void adapteeMethod() {// TODO: 实现需要适配的方法};// 目标接口class Target {public:virtual void targetMethod() = 0;};// 适配器类class Adapter : public Target {public:Adapter(Adaptee* adaptee) : m_adaptee(adaptee) {}virtual void targetMethod() {m_adaptee->adapteeMethod(); // 调用需要适配的方法 // TODO: 实现对目标接口的转换}private:Adaptee* m_adaptee;};```上述代码中,适配器类持有一个源接口的实例,当调用目标接口时,适配器将调用源接口实例的适配方法,并在转换后实现目标接口的方法。
java设计模式之适配器模式

java设计模式之适配器模式
结构型模式之适配器模式
将⼀个类的接⼝转换成客户希望的另外⼀个接⼝,使得原本由于接⼝不兼容⽽不能⼀起⼯作的那些类能⼀起⼯作。
适配器模式分为:类适配器模式和对象适配器模式。
类适配器模式通过继承和实现⽅式来实现,对象适配器模式通过聚合和组合关系来实现,前者类之间的耦合度⽐后者⾼,且要求程序员了解现有组件库中的相关组件的内部结构,所以应⽤相对较少些。
适配器模式的结构:
适配器模式(Adapter)包含以下主要⾓⾊:
⽬标接⼝(Target):当前系统业务所期待的接⼝,它可以是抽象类或接⼝。
适配者类(Adaptee):它是被访问和适配的现存组件库中的组件接⼝。
适配器类(Adapter):它是⼀个转换器,通过继承或引⽤适配者的对象,把适配者接⼝转换成⽬标接⼝,让客户按⽬标接⼝的格式访问适配者。
类适配器模式:
实现⽅式:定义⼀个适配器类来实现当前系统的业务接⼝,同时⼜继承现有组件库中已经存在的组件。
类适配器模式违背了合成服⽤原则。
类适配器是客户类有⼀个接⼝规范的情况下可⽤,反之不可⽤。
对象适配器模式:
实现⽅式:对象适配器模式可采⽤将现有组件库中已经实现的组件引⼊适配器类中,该类同时实现当前系统的业务接⼝。
注意:还有⼀个适配器模式是接⼝适配器模式,当不希望实现⼀个接⼝中所有的⽅法是,可以创建⼀个抽象类Adapter,实现所有⽅法。
⽽此时我们只需要继承该抽象类即可。
应⽤场景:
以前开发的系统存在满⾜新系统功能需求的类,但其接⼝同新系统的接⼝不⼀致。
使⽤第三⽅提供的组件时,但组件接⼝定义和⾃⼰要求的接⼝定义不同。
C语言和设计模式(适配器模式)

C语⾔和设计模式(适配器模式)⽂章⽬录⼀句话理解1、将⼀个类的接⼝转换成客户希望的另外⼀个接⼝2、使得原本由于接⼝不兼容⽽不能⼀起⼯作的那些类可以⼀起⼯作3、尽可能保持已有的类不变的前提下,适应当前的系统适配器模式实现步骤类适配器1、确定⽬标接⼝2、确定被适配者3、创建适配器(继承⾃被适配者,实现⽬标接⼝)对象适配器1、确定⽬标接⼝2、确定被适配者3、创建适配器(拥有被适配者的对象,实现⽬标接⼝)举例 现在的⽣活当中,我们离不开各种电⼦⼯具。
什么笔记本电脑、⼿机、mp4啊,都离不开充电。
既然是充电,那么就需要⽤到充电器。
其实从根本上来说,充电器就是⼀个个普通的适配器。
什么叫适配器呢,就是把220v、50hz的交流电压编程5~12v的直流电压。
充电器就⼲了这么⼀件事情。
那么,这样的⼀个充电适配器,我们应该怎么⽤c++描述呢?class voltage_12v{public:voltage_12v() {}virtual ~voltage_12v() {}virtual void request() {}};class v220_to_v12{public:v220_to_v12() {}~v220_to_v12() {}void voltage_transform_process() {}};class adapter: public voltage_12v{v220_to_v12* pAdaptee;public:adapter() {}~adapter() {}void request(){pAdaptee->voltage_transform_process();}}; 通过上⾯的代码,我们其实可以这样理解。
类voltage_12v表⽰我们的最终⽬的就是为了获得⼀个12v的直流电压。
当然获得12v可以有很多的⽅法,利⽤适配器转换仅仅是其中的⼀个⽅法。
adapter表⽰适配器,它⾃⼰不能实现220v到12v的转换⼯作,所以需要调⽤类v220_to_v12的转换函数。
8.Adapter适配器模式

适配器模式,使用之处比较特殊,不属于常规设计模式,主要用于不同系统之间的处理。
是将一个类的接口转换成客户希望的另外一个接口。
Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
也是一个比较简单的模式,直接上代码了。
看代码:8.1.解释main(),主程序IUserInfo,本系统内接口CUserInfo,本系统内实现类IOuterUser,外系统接口COuterUser,外系统实现类COuterUserInfo,本系统内适配类说明:COuterUserInfo实现IUserInfo接口,将外部系统实现类COuterUser转换成本系统内的接口I UserInfo。
使用外部数据跟使用本系统内部数据一样。
注意:COuterUserInfo继承了IUserInfo,如果同时继承了COuterUser则是类适配器。
如果COuter UserInfo只是使用了COuterUser则是对象适配器。
//IUserInfo.h//系统内部的实体接口#pragma once#include <iostream>using std::string;class IUserInfo{public:IUserInfo(void){}virtual ~IUserInfo(void){}virtual string GetUserName() = 0;virtual string GetHomeAddress() = 0;virtual string GetMobileNumber() = 0;virtual string GetOfficeTelNumber() = 0;virtual string GetJobPosition() = 0;virtual string GetHomeTelNumber() = 0; };//UserInfo.h//系统内部实体类#pragma once#include "iuserinfo.h"#include <iostream>using std::string;class CUserInfo :public IUserInfo{public:CUserInfo(void);~CUserInfo(void);string GetUserName();string GetHomeAddress();string GetMobileNumber();string GetOfficeTelNumber();string GetJobPosition();string GetHomeTelNumber();};//UserInfo.cpp#include "StdAfx.h"#include "UserInfo.h"#include <iostream>using std::cout;using std::endl;using std::string;CUserInfo::CUserInfo(void){}CUserInfo::~CUserInfo(void){}string CUserInfo::GetUserName(){cout << "姓名叫做..." << endl;return "0";}string CUserInfo::GetHomeAddress(){cout << "这里是员工的家庭地址..." << endl;return "0";}string CUserInfo::GetMobileNumber(){cout << "这个人的手机号码是0000..." << endl;return "0";}string CUserInfo::GetOfficeTelNumber(){cout << "办公室电话是..." << endl;return "0";}string CUserInfo::GetJobPosition(){cout << "这个人的职位是BOSS..." << endl;return "0";}string CUserInfo::GetHomeTelNumber(){cout << "员工的家庭电话是..." << endl;return "0";}//IOuterUser.h//外部系统实体接口#pragma once#include "OuterUserBaseInfo.h"#include "OuterUserHomeInfo.h"#include "OuterUserOfficeInfo.h"class IOuterUser{public:IOuterUser(void){}~IOuterUser(void){}COuterUserBaseInfo * GetUserBaseInfo();COuterUserHomeInfo * GetUserHomeInfo();COuterUserOfficeInfo * GetUserOfficeInfo(); };//OuterUser.h//外部系统实体类#pragma once#include "OuterUserBaseInfo.h"#include "OuterUserHomeInfo.h"#include "OuterUserOfficeInfo.h"class COuterUser{public:COuterUser(void){}~COuterUser(void){}COuterUserBaseInfo * GetUserBaseInfo();COuterUserHomeInfo * GetUserHomeInfo();COuterUserOfficeInfo * GetUserOfficeInfo(); };//OuterUser.cpp#include "StdAfx.h"#include "OuterUser.h"#include "OuterUserBaseInfo.h"#include "OuterUserHomeInfo.h"#include "OuterUserOfficeInfo.h"COuterUser::COuterUser(void){}COuterUser::~COuterUser(void){}COuterUserBaseInfo * COuterUser::GetUserBaseInfo() {return new COuterUserBaseInfo();}COuterUserHomeInfo * COuterUser::GetUserHomeInfo() {return new COuterUserHomeInfo();}COuterUserOfficeInfo * COuterUser::GetUserOfficeInfo() {return new COuterUserOfficeInfo();}//OuterUserBaseInfo.h#pragma once#include <iostream>using std::endl;using std::string;class COuterUserBaseInfo{public:COuterUserBaseInfo(void){}~COuterUserBaseInfo(void){}string GetUserName(){cout << "姓名叫做..." << endl;return "0";}string GetMobileNumber(){cout << "这个人的手机号码是0001..." << endl;return "0";}};//OuterUserHomeInfo.h#pragma once#include <iostream>using std::cout;using std::string;class COuterUserHomeInfo{public:COuterUserHomeInfo(void){}~COuterUserHomeInfo(void){}string GetHomeAddress(){cout << "这里是员工的家庭地址..." << endl;return "0";}string GetHomeTelNumber(){cout << "员工的家庭电话是..." << endl;return "0";}};//OuterUserOfficeInfo.h#pragma once#include <iostream>using std::cout;using std::endl;class COuterUserOfficeInfo{public:COuterUserOfficeInfo(void){}~COuterUserOfficeInfo(void){}string GetOfficeTelNumber(){cout << "办公室电话是..." << endl;return "0";}string GetJobPosition(){cout << "这个人的职位是BOSS..." << endl;return "0";}};//OuterUserInfo.h//由IUserInfo接口派生的实体类,并引入外部系统实体的实例#pragma once#include "iuserinfo.h"#include "OuterUser.h"#include <iostream>using std::string;class COuterUserInfo :public IUserInfo{public:COuterUserInfo(void);~COuterUserInfo(void);string GetUserName();string GetHomeAddress();string GetMobileNumber();string GetOfficeTelNumber();string GetJobPosition();string GetHomeTelNumber(); private:COuterUser *m_pOuterUser;};//OuterUserInfo.cpp#include "StdAfx.h"#include "OuterUserInfo.h"#include "OuterUserBaseInfo.h"#include "OuterUserHomeInfo.h"#include "OuterUserOfficeInfo.h"#include <iostream>using std::cout;using std::endl;using std::string; COuterUserInfo::COuterUserInfo(void) {m_pOuterUser = new COuterUser();COuterUserInfo::~COuterUserInfo(void){delete m_pOuterUser;}string COuterUserInfo::GetUserName(){COuterUserBaseInfo *pBaseInfo = m_pOuterUser->GetUserBaseInfo();pBaseInfo->GetUserName();delete pBaseInfo;pBaseInfo = NULL;return "0";}string COuterUserInfo::GetHomeAddress(){COuterUserHomeInfo *pHomeInfo = m_pOuterUser->GetUserHomeInfo();pHomeInfo->GetHomeAddress();delete pHomeInfo;pHomeInfo = NULL;return "0";}string COuterUserInfo::GetMobileNumber(){COuterUserBaseInfo *pBaseInfo = m_pOuterUser->GetUserBaseInfo();pBaseInfo->GetMobileNumber();delete pBaseInfo;pBaseInfo = NULL;return "0";string COuterUserInfo::GetOfficeTelNumber(){COuterUserOfficeInfo *pOfficeInfo = m_pOuterUser->GetUserOfficeInfo();pOfficeInfo->GetOfficeTelNumber();delete pOfficeInfo;pOfficeInfo = NULL;return "0";}string COuterUserInfo::GetJobPosition(){COuterUserOfficeInfo *pOfficeInfo = m_pOuterUser->GetUserOfficeInfo();pOfficeInfo->GetJobPosition();delete pOfficeInfo;pOfficeInfo = NULL;return "0";}string COuterUserInfo::GetHomeTelNumber(){COuterUserHomeInfo *pHomeInfo = m_pOuterUser->GetUserHomeInfo();pHomeInfo->GetHomeTelNumber();delete pHomeInfo;pHomeInfo = NULL;return "0";}//Adapter.cpp//使用方法#include "stdafx.h"#include "IOuterUser.h"#include "IUserInfo.h"#include "UserInfo.h"#include "OuterUserInfo.h"void DoIt(){IUserInfo *pYourGirl = new CUserInfo();for(int i = 0; i < 101; i += 20){pYourGirl->GetMobileNumber();}delete pYourGirl;}void NowDoIt(){IUserInfo *pYourGirl = new COuterUserInfo();for(int i = 0; i < 101; i += 20){pYourGirl->GetMobileNumber();}delete pYourGirl;}int _tmain(int argc, _TCHAR* argv[]){DoIt();NowDoIt();_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);_CrtDumpMemoryLeaks();return 0;}适配器模式属于结构型模式,当出现数据接口不一致的情况下,才会使用到。
深入设计模式(三)——适配器模式

深⼊设计模式(三)——适配器模式⼀、适配器设计模式介绍适配器模式,将⼀个类装换成客户期望的另外⼀个接⼝。
Adapter模式使⽤的原本由于接⼝不兼容⽽不能茉莉花物那些可以⼀起⼯作。
⼆、解决的问题1、使⽤第三⽅组件,⽽这个组件的接⼝与⽬前系统接⼝不兼容(如⽅法与系统⽅法不⼀致等),可以使⽤适配器模式解决接⼝不兼容问题。
2、使⽤早前项⽬⼀些有⽤的类,可以⽤适配器模式解决现有接⼝与原有对象接⼝不兼容问题。
三、⽣活中的例⼦适配器模式允许将⼀个类的接⼝转换成客户期望的另⼀个接⼝,使⽤原本由于接⼝不兼容⽽不能⼀起⼯作的类可以⼀起⼯作。
扳⼿提供了⼀个适配器的例⼦。
⼀个孔套在棘齿上,棘齿的每个边的尺⼨是相同的。
在美国典型的连长为1/2和1/4。
显然,如果不使⽤⼀个适配器的话,1/2的棘齿不能适合1/4的孔。
⼀个1/2到1/4的适配器具有⼀个1/2的阴槽来套上⼀个1/2的齿,同时有⼀个1/4的阳槽来卡⼊1/4的扳⼿。
四、适配器分析1.适配器模式结构2.代码1using System;2using System.Collections.Generic;3using System.Linq;4using System.Text;5using System.Threading.Tasks;67namespace适配器模式8 {9///<summary>10///客户期待的接⼝或者抽象类Target11///</summary>12public abstract class Target13 {14public abstract void Request();15 }16 }客户期待的接⼝或者抽象类Target1using System;2using System.Collections.Generic;3using System.Linq;4using System.Text;5using System.Threading.Tasks;67namespace适配器模式8 {9///<summary>10///要适配的类Adaptee,也就是与期望调⽤接⼝不相符的类11///</summary>12public class Adaptee13 {14public void SpecificReques() {15 Console.WriteLine("执⾏要适配类的特殊请求⽅法");16 }17 }18 }要适配的类Adaptee,也就是与期望调⽤接⼝不相符的类1using System;2using System.Collections.Generic;3using System.Linq;4using System.Text;5using System.Threading.Tasks;67namespace适配器模式8 {9public class Adapter:Target10 {11private Adaptee adaptee;12public override void Request()13 {14if (adaptee == null) {15 adaptee = new Adaptee();16 }17 adaptee.SpecificReques();18 }19 }20 }适配器类Adapter,把源接⼝转换成⽬标接⼝,包⾏变量adaptee1using System;2using System.Collections.Generic;3using System.Linq;4using System.Text;5using System.Threading.Tasks;67namespace适配器模式8 {9///<summary>10///适配器模式,将⼀个类装换成客户期望的另外⼀个接⼝。
一文彻底弄懂适配器模式(Adapter)

⼀⽂彻底弄懂适配器模式(Adapter)⽂章已收录我的仓库:设计意图适配器模式(Adapter Pattern)是作为两个不兼容的接⼝之间的桥梁。
这种类型的设计模式属于结构型模式,它结合了两个独⽴接⼝的功能。
在某些时候,客户期望获得某种功能接⼝但现有的接⼝⽆法满⾜客户的需求,例如美国的正常供电电压为110V,⼀个中国⼈带了⼀款中国制造电器去美国,这个电器必须要在220V电压下才能充电使⽤。
这种情况下,客户(中国⼈)的期望接⼝是有⼀个220V的电压为电器充电,但实际的接⼝是仅有⼀个110V的电压供电器充电,这种情况下就需要采⽤⼀根电压转换器(适配器)使得110V的电压能够转换为220V的电压,供客户使⽤。
将⼀个类的接⼝转换成客户希望的另外⼀个接⼝,这就是适配器需要做的事情,适配器模式使得原本由于接⼝不兼容⽽不能⼀起⼯作的那些类可以⼀起⼯作。
适⽤条件系统需要使⽤现有的类,⽽此类的接⼝不符合系统的需要(核⼼需求)。
想要建⽴⼀个可以重复使⽤的适配器类,⽤于与⼀些彼此之间没有太⼤关联的⼀些类,包括⼀些可能在将来引进的类⼀起⼯作,这些源类不⼀定有⼀致的接⼝,但通过适配器使得它们都具有⼀致的接⼝。
通过接⼝转换,将⼀个类插⼊另⼀个类系中。
(⽐如⽼虎和飞禽,现在多了⼀个飞虎,在不增加实体的需求下,增加⼀个适配器,在⾥⾯包容⼀个虎对象,实现飞的接⼝。
)设计通常有两种⽅式实现适配器模式,⼀种是类适配器,类适配器⽬前已不太使⽤,另⼀种实现⽅式是对象适配器,通常情况下采⽤对象适配器会使得代码更易扩展与维护。
不管采⽤何种⽅式,其基本的实现思想都是:对现有接⼝的实现类进⾏扩展,使其实现客户期望的⽬标接⼝。
类适配器通过继承现有接⼝类并实现⽬标接⼝,这样的话会使得现有接⼝类完全对适配器暴露,使得适配器具有现有接⼝类的全部功能,破坏了封装性。
此外从逻辑上来说,这也是不符合常理的,适配器要做的是扩展现有接⼝类的功能⽽不是替代,类适配器只有在特定条件下会被使⽤。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
类适配器效果 ① 用 Adapter 类对 Adaptee 和 Target 进行匹配。
当想要匹配一个类以及所有它的子类时,
类Adapter将不能胜任工作 ② 使得Adapter可以重定义 Adaptee 的部分行 为,因为Adapter是Adaptee的一个子类。 ③ 仅仅引入一个对象,并不需要额外的指针 以间接得到adaptee
双向适配器
在对象适配器的使用过程中,如果在适配
器中同时包含对目标类和适配者类的引用 适配者可以通过它调用目标类中的方法, 目标类也可以通过它调用适配者类中的方 法,那么该适配器就是一个双向适配器。
双向适配器
Target + request () ...
target adaptee
Adaptee + specificRequest () ...
由于 Adapter与Adaptee是委派关系,这决定
了这个适配器模式是对象的
//目标 public interface ITarget { // Methods void Request(); }
//被适配者 public class Adaptee { public void SpecificRequest() // Methods { System.out.println("Called SpecificRequest()" ); } }
概念理解
适配器模式 把一个类的接口(被适配者)变换成客户端所期待的另一种 接口(目标),从而使原本因接口原因不匹配而无法一起 工作的两个类能够一起工作。
该模式中涉及有目标、被适配者和适配器。
适配器模式的关键是建立一个适配器,这个适 配器实现了目标接口并包含有被适配者的引用。
别名:包装器(Wrapper),变压器模式
办法之一
New System
B
办法之二
System
A
B
Adapter
第二种方案的优点
System
Adapter
B
不需要修改代码
新代码
不需要修改代码
办法之三
System
B’
B
示 例
鸭子接口 public interface Duck { public void quack(); public void fly(); }
适配器模式的结构与使用
适配器模式的两种形式:
①类的适配器模式 ②对象的适配器模式
类的适配器模式(Class Adapter)结构
Client Target + request () ... Adaptee + specificRequest () ...
Adapter + request () ...
// 适配器 public class Adapter extends Adaptee implements ITarget { public void Request() { this.SpecificRequest(); } }
public class Client { public static void main(String[] args) { ITarget t = new Adapter(); t.Request(); } }
问题?
我们原来有一个程序使用鸭子对象,现在 想让它使用火鸡对象,但是火鸡与鸭子的 接口不同,不能直接使用。 写一个火鸡适配器,让火鸡看起来像鸭子
火鸡适配器
public class TurkeyAdapter implements Duck { Turkey turkey; public TurkeyAdapter(Turkey turkey) { this.turkey = turkey; } 火鸡适配器包装了一 public void quack() { 个火鸡对象,同时实 现了鸭子接口。这样 turkey.gobble(); 就可以像使用鸭子一 } 样使用火鸡了。 public void fly() { for(int i=0; i < 5; i++) { turkey.fly(); } } }
Adapter(适配器)模式 接口转换
请求 客户
转换后的请求
适配器
面向对象软件系统的适配问题 假设我们已经有一个软件系统,原来使用 了一个第三方类库A。现在有一个新的第三 方类库B,其功能等各方面都更加强大。 我们希望用 B来替换 A ,以改善我们的系统。 但是B的接口与A不一样。那怎么办呢?
ConcreteTarget + request () ... adaptee.specificRequest();
Adapter - adaptee : Adaptee - target : Target + request () + specificRequest () + setTarget (Target target) + setAdaptee (Adaptee adaptee) ...
MallardDuck类简单地 实现了Duck接口。
现在有一种新家伙
public interface Turkey { public void gobble(); public void fly(); }
WildTurkey
public class WildTurkey implements Turkey { public void gobble() { System.out.println("咕咕咕..."); } public void fly() { System.out.println("我在飞,不过飞不远"); } }
组合成一个更大的系统,在类结构型模式中
一般只存在继承关系和实现关系。
对象结构型模式关心类与对象的组合,通过
关联关系使得在一个类中定义另一个类的实
例对象,然后通过该对象调用其方法。
结构型模式
根据“合成复用原则”,在系统中尽量 使用组合关系来替代继承关系,因此大
部分结构型模式都是对象结构型模式。
结构型模式
对象适配器模式(Object Adapter)结构
Client Target + request () ... Adaptee + specificRequest () ...
Adapter + request () ...
adaptee
adaptee.specificRequest();
客户端需要调用 Request 方法,而 Adaptee 没 有该方法,为了使客户端能够使用 Adaptee 类,需要提供类Adapter Adapter包装一个 Adaptee的实例,从而将客 户端与Adaptee衔接起来
对象适配器效果
① 允许一个Adapter与多个Adaptee及它们所
有子类同时工作。 Adapter 也可以一次给
所有的Adaptee添加功能 ② 使得重定义 Adaptee 的行为比较困难。这 就 需 要 生 成 Adaptee 的 子 类 并 且 使 得 Adapter引用这个子类而不是引用Adaptee 本身。
使用适配器ห้องสมุดไป่ตู้
public class DuckTestDrive { public static void main(String[] args) { MallardDuck duck = new MallardDuck(); WildTurkey turkey = new WildTurkey(); Duck turkeyAdapter = new TurkeyAdapter(turkey); System.out.println("火鸡说..."); turkey.gobble(); 在需要鸭子对象的 turkey.fly(); 地方使用了火鸡适 System.out.println("\n鸭子说..."); 配器对象, 火鸡适 testDuck(duck); 配器对象包装了一 System.out.println("\n火鸡适配器说..."); 个火鸡对象,所以 testDuck(turkeyAdapter); 实际使用的是火鸡 } 对象。 static void testDuck (Duck duck) { duck.quack(); duck.fly(); } } 需要使用鸭子对象
分 析
目标接口:鸭子接口
被适配者
适配器
客户 要使用鸭子 对象的程序
火鸡接口
把火鸡装 扮成鸭子
两者无耦合 彼此不必知道对方的存在
试试看
如果希望把鸭子包装成火鸡该怎么做? 写出你的代码DuckAdapter
DuckAdapter
import java.util.Random; public class DuckAdapter implements Turkey { Duck duck; Random rand; public DuckAdapter(Duck duck) { this.duck = duck; rand = new Random(); } public void gobble() { duck.quack(); } public void fly() { if (rand.nextInt(5) == 0) { duck.fly(); } } }
specificRequest();
客户Client
目标(Target) 客户所期待的接口
被适配者( Adaptee ):一个已经存在的、需
要适配的类,它具有Client要求的功能但不符
合Client的接口要求
适配器(Adapter)
对Adaptee的接口与Target接口进行适配
适配器模式的核心类