设计模式Adapter

上传人:fgh****35 文档编号:172624821 上传时间:2022-12-05 格式:DOCX 页数:19 大小:150.10KB
返回 下载 相关 举报
设计模式Adapter_第1页
第1页 / 共19页
设计模式Adapter_第2页
第2页 / 共19页
设计模式Adapter_第3页
第3页 / 共19页
点击查看更多>>
资源描述
A:一书中的描述将一个类的接口转换成客户希望的另一个接口,Adapter模式使原本由于接口不兼容而不能一起工作的类可以一起工作简单的说,就是利用现有的接口去包装一个第三方的接口, 使其能象现有接口一样被程序调用,而不考虑实际使用类的差异举例:当前系统有一个绘图接口 IDraw , 其中定义了display()方法,用来显示一个现在同事A,给我一套新的绘图类,但是这个类却使用了show()方法来显示一个图形我不能修改这个新接口,因为他被编译了,如果直接使用此接口,我不得不修改主程序以适应这个接口,这是一个繁重的工作但是,使用Adapter模式,可以根据IDraw接口来创建一个适配器class MyDraw implements IDraw OtherDraw otherDraw = new OtherDraw(); public void display() otherDraw.show(); 现在我们可以调用MyDraw的display()方法来显示图形了,主程序不会意识到下端子系统的变化Adapter模式与Facade模式很相象他们都封装了原有的接口他们之间的区别在于Facade模式不按照某个接口设计 Adapter模式必须按照某个类设计Facade一般不需要多态行为 Adapter模式大多可能是为了现有的多态行为而使用的Facade是为了简化原有的复杂接口 Adapter必须遵循一个已有的接口,不能简化任何东西,即使可能存在更简单的接口B: 意图将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。(GoF)场景相信很多人都知道什么是显卡,也有很多人知道显卡的本名图形适配器。恩,是的,正好这回说说Apater模式,就拿显卡来例子来分析一下Adapter模式。我们知道显示器(Client)是用来显示图形的,它是不能显示数据,它只能够接受来自图形发送设备Target的信号。可是我们手头上只有CPU(Adaptee)这个产生各种描述图形的数据的数据发送器。我们需要将这些数据让显示器进行显示,可是这两个部件却是不兼容的。于是我们需要一个中间设备,它能够将CPU“适配”于显示器,这便是我们的显卡图形适配器(Adapter)。java 代码1. /图形发送设备2. publicclassTarget3. /*4. *传送图形信号5. */6. publicStringrequest()7. returnGraphicsender;8. 9. java 代码1. /显示器2. publicclassClient3. 4. publicstaticvoidmain(Stringargs)5. Targettarget=newTargete();6. System.out.println(target.request();7. 8. 可是我们的CPU(Adaptee)只能输出0/1数据,他是个计算器,而不是图形发送设备(Target)。java 代码1. /CPU2. publicclassAdaptee3. /*4. *CPU输出的数据5. */6. publicStringgetData()7. returnCPUdata;8. 9. 这个时候我们的显卡(Adapter)的作用便体现出来了,它负责对CPU进行适配,通过将CPU传过来的数据转换成图形信号,从而将CPU伪装成一个图形发送设备。java 代码1. /显卡,即我们的适配器2. publicclassAdapterextendsTarget3. 4. /被代理的设备5. privateAdapteeapt=null;6. 7. /*8. *装入被代理的设备9. */10. publicAdapter(Adapteeapt)11. this.apt=apt;12. 13. 14. /*15. *被代理的设备传过来的数据转换成为图形输出16. */17. publicStringrequest()18. returnapt.getData();19. 20. 这样,我们的电脑的显示流程就变成CPU显卡显示器:java 代码1. publicclassClient2. 3. publicstaticvoidmain(Stringargs)4. /CPU经过显卡的适配后“变”成了图形发送装置了5. Targettarget=newAdapter(newAdaptee();6. System.out.println(target.request();7. 8. 9. 上面的这种依赖于对象组合的Adapter模式叫做对象适配器(Object Adapter)。它的特征是继承/实现某一方的类(Target),如这里的图形发送器,同时内部包含一个被适配的类(Adaptee),如这里的CPU。通过重写其父类的方法来进行适配。另一种的Adapter实现对于Adapter模式,还有另外一种实现方式,这种适配方式叫做类适配器(Class Adapter)。它与Object Adapter的不同之处在于它继承被适配的对象。java 代码1. publicclassAdapterextendsTarger,Adaptee2. .3. 这样的代码在C+中是合法的,但是在Java中规定最多只能继承一个父类,而可以实现多个接口。所以我们需要建立一个IAdaptee的接口,然后将我们的Adapter继承Target同时实现IAdaptee。java 代码1. /IAdaptee接口2. publicinterfaceIAdaptee 3.4. String getData();5. java 代码1. / Adaptee 实现IAdaptee 2. publicclass Adaptee implementsIAdaptee 3. .4. java 代码1. publicclassAdapterextendsTargetimplementsIAdaptee2. 3. privateIAdapteeapt=null;4. 5. publicAdapter(IAdapteeapt)6. this.apt=apt;7. 8. 9. publicStringrequest()10. returnapt.getData();11. 12. 13. publicStringgetData()14. returnapt.getData();15. 16. 对于我们的显示器(Client)方面,Class Adapter跟Object Adapter一样,所以不需要进行修改。对于Class Adapter,大家也看见了,在Adapter中因为是实现了IAdaptee接口,因此需要实现getData()的接口。一旦Target和IAdaptee拥有相同的方法时,会出现麻烦的。所以尽量优先使用Object Adapter的模式C: 工作一年多了,纸上的笔记写了不少,但一直没有机会整理。现在离职了,就用这段时间整理一下自己的笔记,也顺便丰富一下自己的博客吧,要不也真的对不起在这里潜水两年的时间。 适配器:基于现有类所提供的服务,向客户提供接口,以满足客户的期望 Java设计模式 类适配器 客户的开发人员定义了一个接口,期望用这个接口来完成整数的求和操作,接口定义如下: Java代码 1. publicinterfaceOperation 2. publicintadd(inta,intb); 3. public interface Operation public int add(int a,int b);开发人员在了解这个接口的定义后,发现一个第三方类,里面有一个方法能实现他们期望的功能,其代码如下: Java代码 1. publicclassOtherOperation 2. publicintotherAdd(inta,intb) 3. returna+b; 4. 5. public class OtherOperation public int otherAdd(int a,int b) return a + b; 以上第三方类OtherOperation的方法public int otherAdd(int a,int b)所提供的功能,完全能符合客户的期望,所以只需要想办法把OtherOperation的otherAdd(int a,int b)和客户的Operation接口联系起来,让这个第三方类来为客户提供他们期望的服务就行了,这样就避免了开发人员再度去研究类似OtherOperation的otherAdd(int a,int b)方法的实现(利用已有的轮子,避免重复发明),这方法之一,就是用适配器模式: Java代码 1. publicclassAdapterOperationextendsOtherOperationimplementsOperation 2. publicintadd(inta,intb) 3. returnotherAdd(a,b); 4. 5. public class AdapterOperation extends OtherOperation implements Operation public int add(int a,int b) return otherAdd(a,b); 以上就是适配器的实现方法之一,类适配器,在以上实现中存在着三中角色分别是: 1:适配目标角色:Operation。 2:适配类(原)角色:OtherOperation。 3:适配器角色:AdapterOperation。 其中适配器角色是适配器模式的核心。 适配器的主要工作就是通过封装现有的功能,使他满足需要的接口。 对象适配器 我们再来看看另一种情况: 假如客户接口期望的功能不止一个,而是多个: Java代码 1. publicinterfaceOperation 2. publicintadd(inta,intb); 3. publicintminus(inta,intb); 4. publicintmultiplied(inta,intb); 5. public interface Operation public int add(int a,int b); public int minus(int a,int b); public int multiplied(int a,int b);而能提供这些实现的原可能不止一个: Java代码 1. publicclassOtherAdd 2. publicintotherAdd(inta,intb) 3. returna+b; 4. 5. 6. 7. publicclassOtherMinus 8. publicintminus(inta,intb) 9. returna-b; 10. 11. 12. 13. publicclassOtherMultiplied 14. publicintmultiplied(inta,intb) 15. returna*b; 16. 17. public class OtherAdd public int otherAdd(int a,int b) return a + b; public class OtherMinus public int minus(int a,int b) return a - b; public class OtherMultiplied public int multiplied(int a,int b) return a * b; 由于java是不能实现多继承的,所以我们不能通过构建一个适配器,让他来继承所有原以完成我们的期望,这时候怎么办呢?只能用适配器的另一种实现-对象适配器: Java代码 1. publicclassAdapterOperationimplementsOperation 2. privateOtherAddadd; 3. privateOtherMinusminus; 4. privateOtherMultipliedmultiplied; 5. 6. publicvoidsetAdd(OtherAddadd) 7. this.add=add; 8. 9. 10. publicvoidsetMinus(OtherMinusminus) 11. this.minus=minus; 12. 13. 14. publicvoidsetMultiplied(OtherMultipliedmultiplied) 15. this.multiplied=multiplied; 16. 17. 18. /适配加法运算 19. publicintadd(inta,intb) 20. returnadd.otherAdd(a,b); 21. 22. 23. /适配减法运算 24. publicintminus(inta,intb) 25. returnminus.minus(a,b); 26. 27. 28. /适配乘法运算 29. publicintmultiplied(inta,intb) 30. returnmultiplied.multiplied(a,b); 31. 32. public class AdapterOperation implements Operation private OtherAdd add; private OtherMinus minus; private OtherMultiplied multiplied; public void setAdd(OtherAdd add) this.add = add; public void setMinus(OtherMinus minus) this.minus = minus; public void setMultiplied(OtherMultiplied multiplied) this.multiplied = multiplied; /适配加法运算 public int add(int a,int b) return add.otherAdd(a,b); /适配减法运算 public int minus(int a,int b) return minus.minus(a,b); /适配乘法运算 public int multiplied(int a,int b) return multiplied.multiplied(a,b); 上面代码很明显,适配器并不是通过继承来获取适配类(原)的功能的,而是通过适配类的对象来获取的,这就解决了java不能多继承所带来的不便了。这也是java提倡的编程思想之一,即尽量使用聚合不要使用继承。 还有一种情况是需要使用对象适配器的。我们来看看, 单我们的客户提供的需求并不是一个明确的接口,而是一个类,并没有定义期望的方法,如下 Java代码 1. publicclassA 2. publicintadd(inta,intb) 3. returna+b; 4. 5. public class A public int add(int a,int b) return a + b; 现在客户要一个新类B,要求能在保留类A功能的情况下增加一个运算减法的功能,并要求B能随时替换掉A但不能对已有系统造成影响。这样我们只能新建一个类B,并让B继承A。 Java代码 1. publicclassBextendsA 2. b() 3. super(); 4. 5. 6. publicintminus(inta,intb) 7. /待实现的减法运算函数. 8. 9. public class B extends A b() super(); public int minus(int a,int b) /待实现的减法运算函数. 这时候,我们发现类C已经提供了实现减法的函数, Java代码 1. publicclassC 2. publicintminus(inta,intb) 3. returna-b; 4. 5. public class C public int minus(int a,int b) return a - b; 为了避免重复去设计该函数,我们决定引入C类,通过适配C类来达到我们的期望,但问题是A和C都是一个具体类,我们无法让B同时继承这个两个类,而B继承A又是必须的,所以我们只能考虑把C给内聚到B内部,对象适配器又得派上用场了。 Java代码 1. publicclassBextendsA 2. 3. privateCc; 4. 5. B() 6. super(); 7. 8. 9. publicvoidsetMinus(Cc) 10. this.c=c; 11. 12. 13. publicintminus(inta,intb) 14. returnc.minus(a,b); 15. 16. public class B extends A private C c; B() super(); public void setMinus(C c) this.c= c; public int minus(int a,int b) return c.minus(a,b); 这样,在需要A类的地方都能用B类来代替,同时又保证了新的功能的引入。 更灵活的实现-隐藏目标接口的抽象适配器 做java 桌面应用的都知道WindowListener接口, Java代码 1. publicinterfaceWindowListenerextendsEventListener 2. publicvoidwindowActivated(WindowEvente); 3. publicvoidwindowClosed(WindowEvente); 4. publicvoidwindowClosing(WindowEvente); 5. publicvoidwindowDeactivated(WindowEvente); 6. publicvoidwindowDeiconified(WindowEvente); 7. publicvoidwindowIconified(WindowEvente); 8. publicvoidwindowOpened(WindowEvente); 9. public interface WindowListener extends EventListener public void windowActivated(WindowEvent e); public void windowClosed(WindowEvent e); public void windowClosing(WindowEvent e); public void windowDeactivated(WindowEvent e); public void windowDeiconified(WindowEvent e); public void windowIconified(WindowEvent e); public void windowOpened(WindowEvent e);要实现这个接口,我们就必须实现它所定义的所有方法,但是实际上,我们很少需要同时用到所有的方法,我们要的只是其中的两三个。为了不使我们实现多余的方法, jdk WindowListener提供了一个WindowListener的默认实现类WindowAdapter类,这是一个抽象类, Java代码 1. publicabstractclassWindowAdapterimplementsWindowListener 2. publicvoidwindowActivated(WindowEvente) 3. publicvoidwindowClosed(WindowEvente) 4. publicvoidwindowClosing(WindowEvente) 5. publicvoidwindowDeactivated(WindowEvente) 6. publicvoidwindowDeiconified(WindowEvente) 7. publicvoidwindowIconified(WindowEvente) 8. publicvoidwindowOpened(WindowEvente) 9. public abstract class WindowAdapter implements WindowListener public void windowActivated(WindowEvent e) public void windowClosed(WindowEvent e) public void windowClosing(WindowEvent e) public void windowDeactivated(WindowEvent e) public void windowDeiconified(WindowEvent e) public void windowIconified(WindowEvent e) public void windowOpened(WindowEvent e)WindowAdapter类对WindowListener接口的所有有方法都提供了空实现, 有了WindowAdapter类,我们只需要去继承WindowAdapter,然后选择我们所关心的方法来实现就行了,这样就避免了直接去实现WindowListener接口。2009-08-19java Adapter模式关键字: android adapter 通常,客户类(clients of class)通过类的接口访问它提供的服务。有时,现有的类(existing class)可以提供客户类的功能需要,但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口太详细或者缺乏详细或接口的名称与客户类所查找的不同等诸多不同原因导致的。 在这种情况下,现有的接口需要转化(convert)为客户类期望的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类所提供的功能。适配器模式(Adapter Pattern)可以完成这样的转化。适配器模式建议定义一个包装类,包装有不兼容接口的对象。这个包装类指的就是适配器(Adapter),它包装的对象就是适配者(Adaptee)。适配器提供客户类需要的接口,适配器接口的实现是把客户类的请求转化为对适配者的相应接口的调用。换句话说:当客户类调用适配器的方法时,在适配器类的内部调用适配者类的方法,这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作(work together)。 在上面讨论的接口: (1) 不是指在JAVA编程语言中接口的概念,虽然类的接口可以通过JAVA借扩来定义。 (2) 不是指由窗体和GUI控件所组成的GUI应用程序的用户接口。 (3) 而是指类所暴露的,被其他类调用的编程接口, 类适配器(Class Adapter)VS对象适配器(Object Adapter) 适配器总体上可以分为两类:类适配器(Class Adapter)VS对象适配器(Object Adapter) 类适配器: 类适配器是通过继承类适配者类(Adaptee Class)实现的,另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候,适配器内部调用它所继承的适配者的方法。 对象适配器: 对象适配器包含一个适配器者的引用(reference),与类适配器相同,对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候,对象适配器调它所包含的适配器者实例的适当方法。 下表是类适配器(Class Adapter)和对象适配器(Object Adapter)的详细不同: 补充: 类适配器(Class Adapter) 对象适配器(Object Adapter) 基于继承概念 利用对象合成 只能应用在适配者是接口,不能利用它子类的接口,当类适配器建立时,它就静态地与适配者关联 可以应用在适配者是接口和它的所有子类,因为适配器是作为适配者的子类,所以适配器可能会重载适配者的一些行为。 注意:在JAVA中,子类不能重载父类中声明为final的方法。 不能重载适配者的方法。 注意:字面上,不能重栽只是因为没有继承。但是适配器提供包装方法可以按需要改变行为。 客户类对适配者中声明为public的接口是可见的, 客户类和适配者是完全不关联的,只有适配器才能感知适配者接口。 在JAVA应用程序中: 适用于期待的接口是JAVA接口的形式,而不是抽象地或具体地类的形式。这是因为JAVA编程语言只允许单继承。因此,类适配器设计成适配者的子类。 在JAVA应用程序中: 适用于当客户对象期望的接口是抽象类的形式,同时也可以应用于期望接口是Java接口的形式。 例子: 让我们建立一个验证给定客户地址的应用。这个应用是作为大的客户数据管理应用的一部分。 让我们定义一个Customer类: Java代码 1. classCustomer 2. publicstaticfinalStringUS=US; 3. publicstaticfinalStringCANADA=Canada; 4. privateStringaddress; 5. privateStringname; 6. privateStringzip,state,type; 7. publicbooleanisValidAddress() 8. 9. 10. 11. publicCustomer(Stringinp_name,Stringinp_address, 12. Stringinp_zip,Stringinp_state, 13. Stringinp_type) 14. name=inp_name; 15. address=inp_address; 16. zip=inp_zip; 17. state=inp_state; 18. type=inp_type; 19. 20. /endofclassclass Customer public static final String US = US; public static final String CANADA = Canada; private String address; private String name; private String zip, state, type; public boolean isValidAddress() public Customer(String inp_name, String inp_address, String inp_zip, String inp_state, String inp_type) name = inp_name; address = inp_address; zip = inp_zip; state = inp_state; type = inp_type; /end of class不同的客户对象创建Customer对象并调用(invoke)isValidAddress方法验证客户地址的有效性。为了验证客户地址的有效性,Customer类期望利用一个地址验证类(address validator class),这个验证类提供了在接口AddressValidator中声明的接口。 Java代码 1. 2. publicinterfaceAddressValidator 3. publicbooleanisValidAddress(Stringinp_address, 4. Stringinp_zip,Stringinp_state); 5. /endofclass public interface AddressValidator public boolean isValidAddress(String inp_address, String inp_zip, String inp_state);/end of class让我们定义一个USAddress的验证类,来验证给定的U.S地址。 Java代码 1. classUSAddressimplementsAddressValidator 2. publicbooleanisValidAddress(Stringinp_address, 3. Stringinp_zip,Stringinp_state) 4. if(inp_address.trim().length()10) 5. returnfalse; 6. if(inp_zip.trim().length()10) 9. returnfalse; 10. if(inp_state.trim().length()!=2) 11. returnfalse; 12. returntrue; 13. 14. /endofclassclass USAddress implements AddressValidator public boolean isValidAddress(String inp_address, String inp_zip, String inp_state) if (inp_address.trim().length() 10) return false; if (inp_zip.trim().length() 10) return false; if (inp_state.trim().length() != 2) return false; return true; /end of classUSAddress类实现AddressValidator接口,因此Customer对象使用USAddress实例作为验证客户地址过程的一部分是没有任何问题的。 Java代码 1. classCustomer 2. 3. 4. publicbooleanisValidAddress() 5. /getanappropriateaddressvalidator 6. AddressValidatorvalidator=getValidator(type); 7. /Polymorphiccalltovalidatetheaddress 8. returnvalidator.isValidAddress(address,zip,state); 9. 10. privateAddressValidatorgetValidator(StringcustType) 11. AddressValidatorvalidator=null; 12. if(custType.equals(Customer.US) 13. validator=newUSAddress(); 14. 15. returnvalidator; 16. 17. /endofclassclass Customer public boolean isValidAddress() /get an appropriate address validator AddressValidator validator = getValidator(type); /Polymorphic call to validate the address return validator.isValidAddress(address, zip, state);private AddressValidator getValidator(String custType) AddressValidator validator = null; if (custType.equals(Customer.US) validator = new USAddress(); return validator;/end of class但是当验证来自加拿大的客户时,就要对应用进行改进。这需要一个验证加拿大客户地址的验证类。让我们假设已经存在一个用来验证加拿大客户地址的使用工具类CAAddress。 从下面的CAAdress类的实现,可以发现CAAdress提供了客户类Customer类所需要的验证服务。但是它所提供的接口不用于客户类Customer所期望的。从下面的CAAdress类的实现,可以发现CAAdress提供了客户类Customer类所需要的验证服务。但是它所提供的接口不用于客户类Customer所期望的。 Java代码 1. classCAAddress 2. publicbooleanisValidCanadianAddr(Stringinp_address, 3. Stringinp_pcode,Stringinp_prvnc) 4. if(inp_address.trim().length()15) 5. returnfalse; 6. if(inp_pcode.trim().length()!=6) 7. returnfalse; 8. if(inp_prvnc.trim().length()6) 9. returnfalse; 10. returntrue; 11. 12. /endofclassclass CAAddress public boolean isValidCanadianAddr(String inp_address, String inp_pcode, String inp_prvnc) if (inp_address.trim().length() 15) return false; if (inp_pcode.trim().length() != 6) return false; if (inp_prvnc.trim().length() 6) return false; return true; /end of classCAAdress类提供了一个isValidCanadianAddr方法,但是Customer期望一个声明在AddressValidator接口中的isValidAddress方法。 接口的不兼容使得Customer对象利用现有的CAAdress类是困难的。一种意见是改变CAAdress类的接口,但是可能会有其他的应用正在使用CAAdress类的这种形式。改变CAAdress类接口会影响现在使用CAAdress类的客户。 应用适配器模式,类适配器CAAdressAdapter可以继承CAAdress类实现AddressValidator接口。 Java代码 1. publicclassCAAddressAdapterextendsCAAddress 2. implementsAddressValidator 3. publicbooleanisValidAddress(Stringinp_address, 4. Stringinp_zip,Stringinp_state) 5. returnisValidCanadianAddr(inp_address,inp_zip, 6. inp_state); 7. 8. /endofclasspublic class CAAddressAdapter extends CAAddress implements AddressValidator public boolean isValidAddress(String inp_address, String inp_zip, String inp_state) return isValidCanadianAddr(inp_address, inp_zip, inp_state); /end of class因为适配器CAAdressAdapter实现了AddressValidator接口,客户端对象访问适配器CAAdressAdapter对象是没有任何问题的。当客户对象调用适配器实例的isValidAddress方法的时候,适配器在内部把调用传递给它继承的isValidCanadianAddr方法。 在Customer类内部,getValidator私有方法需要扩展,以至于它可以在验证加拿大客户的时候返回一个CAAdressAdapter实例。返回的对象是多态的,USAddress和CAAddressAdapter都实现了AddressValidator接口,所以不用改变。 Java代码 1. classCu
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 商业管理 > 营销创新


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!