第9讲 适配器模式
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
分析
WebFormDesigner在本例中是Adaptee, WebFormDesigner_text_actionAdapter在本例中是Adapter, java.awt.event.ActionListener在本例中是适配目标。 适配目标为一接口,代码如下: public interface ActionListener extends EventListener { /** * Invoked when an action occurs. */ public void actionPerformed(ActionEvent e); } 适配目标中只有一个方法:actionPerformed()。由于 WebFormDesigner_text_actionAdapter 实现了 java.awt.event.ActionListener,所以要求实现actionPerformed()方法。 WebFormDesigner_text_actionAdapter实现actionPerformed()方法是引 用了WebFormDesigner这个adaptee来完成的。从代码中可以看出, WebFormDesigner是WebFormDesigner_text_actionAdapter的方法的参数, 所以WebFormDesigner_text_actionAdapter依赖WebFormDesigner。 Adaptee类(WebFormDesigner)的方法(text_actionPerformed)与Adapter 类(WebFormDesigner_text_actionAdapte)的方法(actionPerformed) 不同名而实现相同功能,这就是我们上面分析的基于对象的Adapter模式。
The Adaptor Pattern (适配器模式)
现实生活中的适配器
欧式插座
三相转二 相
笔记本电脑 插头
现实生活中的适配器
面向对象软件系统的适配问题
假设我们已经有一个软件系统,原来使 用了一个第三方类库A。现在有一个新的 第三方类库B,其功能等各方面都更加强 大。我们希望用B来替换A,以改善我们 的系统。但是B的接口与A不一样。那怎 么办呢?
Adapter模式
适用性 以下情况使用A d a p t e r模式
你想使用一个已经存在的类,而它的接口不符合你 的需求。 你想创建一个可以复用的类,该类可以与其他不相 关的类或不可预见的类(即那些接口可能不一定兼 容的类)协同工作。
Adapter模式
结构(类版本)
Adapter模式
结构(对象版本)
Adapter模式
效果(类适配器和对象适配器有不同的 权衡)
对象适配器则
允许一个A d a p t e r与多个A d a p t e e—即A d a p t e e 本身以及它的所有子类(如果有子类的话)同时工作。A d a p t e r也可以一次给所有的A d a p t e e添加功能。 使得重定义A d a p t e e的行为比较困难。这就需要生成A d a p t e e的子类并且使得A d a p t e r引用这个子类而不 是引用A d a p t e e本身。
鸭子接口Duck,定 义了鸭子具有“鸣 叫”和“飞行”方 法
MallardDuck类
public class MallardDuck implements Duck { public void quack() { System.out.println(" 嘎嘎嘎..."); } public void fly() { System.out.println(" 我在飞哦!"); } }
Adapter模式
协作
Client在A d a p t e r实例上调用一些操作 (请求)。接着适配器调用A d a p t e e的 操作实现这个请求。
Adapter模式
效果(类适配器和对象适配器有不同的权衡)
类适配器
用一个具体的A d a p t e r类对A d a p t e e和Ta rg e t进 行匹配。结果是当我们想要匹配一个类以及所有它的子类 时,类A d a p t e r将不能胜任工作。 使得A d a p t e r可以重定义A d a p t e e的部分行为,因 为A d a p t e r是A d a p t e e的一个子类。 仅仅引入了一个对象,并不需要额外的指针以间接得到a d a p t e e。
分析以下例子,确定各个类的角色
public class WebFormDesigner extends JFrame { void jbInit() throws Exception { text.addActionListener(new WebFormDesigner_text_actionAdapter(this)); } void text_actionPerformed(ActionEvent e) { TextDialog createText = new TextDialog(); createText.setVisible(true); createText.setTitle("TEXT"); createText.setBounds(100, 100, 500, 300); createText.setModal(true); createText.show(); } }
基于对象的Adapter模式的一般结构如下: Adaptee类对象为Adapter所依赖,适配目标 (接口)是Adapter的父类; 基于对象的Adapter模式比较适合应用于 Adapter想为Adaptee添加新的方法的情况。但 在Adaptee类的方法与Adapter类的方法不同名 而实现相同功能的情况下,我们一般也使用基 于对象的Adapter模式,
Adapter模式
动机(续)
我们可以不用上面的方法,而定义一个适配器类, 由它来适配工具箱的接口和专业应用的接口。我们 可以用两种方法做这件事: 1) 继承专业应用类的接口和工具箱类的实现。这种 方法对应A d a p t e r模式的类版本(多继承) 2) 将工具箱类的实例作为适配器类的组成部分,并 且使用工具箱的接口实现适配器类。这种方法对应 A d a p t e r模式的对象版本。
分析以下例子,确定各个类的角色---续
class WebFormDesigner_text_actionAdapter implements java.awt.event.ActionListener { WebFormDesigner adaptee; WebFormDesigner_text_actionAdapter(WebFormDesigner adaptee) { this.adaptee = adaptee; } public void actionPerformed(ActionEvent e) { adaptee.text_actionPerformed(e); } }
Adapter模式
参与者
Ta r g e t
C l i e n t使用的与特定领域相关的“接口”。
Client
与符合Ta rg e t接口的对象协同的专业系统。
Adaptee
一个已经存在的“接口”,它具有Client要求的功能但不 符合Client的接口要求。这个接口需要适配。
Adapter
对A d a p t e e的接口与Ta rg e t接口进行适配
适配器模式详解
目标接口:鸭子接口 目标接口 鸭子接口
被适配者 火鸡接口
适配器 把火鸡装 扮成鸭子 两者无耦合 彼此不必知道对方的存在
客户 要使用鸭子 对象的程序
试试看
现在,如果希望把鸭子包装成火鸡该怎 么做? 写出你的代码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(); } } }
火鸡适配器包装 了一个火鸡对象, 同时实现了鸭子 接口。这样就可 以像使用鸭子一 样使用火鸡了。
使用适配器
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鸭子说..."); System.out.println("\n ..."); 鸡适配器对象, testDuck(duck); 火鸡适配器对象 System.out.println("\n火鸡适配器说..."); 包装了一个火鸡 testDuck(turkeyAdapter); 对象,所以实际 } 使用的是火鸡对 static void testDuck(Duck duck) { 象。 duck.quack(); duck.fly(); } } 需要使用鸭子对象
我们原来有一个程序使用鸭子对象,现 在想让它使用火鸡对象,但是火鸡与鸭 子的接口不同,不能直接使用。 写一个火鸡适配器,让火鸡看起来像鸭 子
火鸡适配器
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(); } } }
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("我在飞,不过飞不远。"); } }
基于类的Adapter模式
基于类的Adapter模式的一般结构如下: Adaptee类为Adapter的父类,Adaptee类 为适配源,适配目标(接口)也是 Adapter的父类;基于类的Adapter模式 比较适合应用于Adapter想修改Adaptee 的部分方法的情况。
基于对象的Adapter模式
Adapter模式
定义
将一个类的接口转换成客户端所期望的另一 种接口,从而使原本因接口不匹配而无法在 一起工作的两个类能够在一起工作。
别名
包装器Wrapper
Adapter模式
动机
有时,为复用而设计的工具箱类不能够被复用的原 因仅仅是因为它的接口与专业应用领域所需要的接 口不匹配(名称不一样,参数不一样,等等)。 我们可以改变工具箱类使它兼容专业领域中的类的 接口,但前提是必须有这个工具箱的源代码。然而 即使我们得到了这些源代码,修改工具箱也是没有 什么意义的;因为不应该仅仅为了实现一个应用, 工具箱就不得不采用一些与特定领域相关的接口。
办法之一
New System System
A
B
办法之一
New System
B
办法之二
System
A
B
Adapter
第二种方案的优点
System
Adapter
B
不需要修改代码
新代码
不需要修改代码
办法之三
System
B’
B
下面我们来看一个实际的例子
简化的鸭子接口和类 public interfawenku.baidu.come Duck { public void quack(); public void fly(); }