`
wangxiaohigh
  • 浏览: 1419076 次
文章分类
社区版块
存档分类
最新评论

适配器模式(Adapter Pattern)

 
阅读更多
<!-- end of article title -->
适配器模式(AdapterPattern)
<!--start of article content -->

第20章适配器模式(AdapterPattern)

说明:


通常,客户类(clientsofclass)通过类的接口访问它提供的服务。有时,现有的类(existingclass)可以提供客户类的功能需要,但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口太详细或者缺乏详细或接口的名称与客户类所查找的不同等诸多不同原因导致的。
在这种情况下,现有的接口需要转化(convert)为客户类期望的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类所提供的功能。适配器模式(AdapterPattern)可以完成这样的转化。适配器模式建议定义一个包装类,包装有不兼容接口的对象。这个包装类指的就是适配器(Adapter),它包装的对象就是适配者(Adaptee)。适配器提供客户类需要的接口,适配器接口的实现是把客户类的请求转化为对适配者的相应接口的调用。换句话说:当客户类调用适配器的方法时,在适配器类的内部调用适配者类的方法,这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于借口不兼容而不能交互的类可以一起工作(worktogether)。
在上面讨论的接口:
(1)不是指在JAVA编程语言中接口的概念,虽然类的接口可以通过JAVA借扩来定义。
(2)不是指由窗体和GUI控件所组成的GUI应用程序的用户接口。
(3)而是指类所报漏的,被其他类调用的编程接口,
类适配器(ClassAdapter)VS对象适配器(ObjectAdapter)
适配器总体上可以分为两类??类适配器(ClassAdapter)VS对象适配器(ObjectAdapter)

类适配器:


类适配器是通过继承类适配者类(AdapteeClass)实现的,另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候,适配器内部调用它所继承的适配者的方法。

对象适配器:


对象适配器包含一个适配器者的引用(reference),与类适配器相同,对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候,对象适配器调它所包含的适配器者实例的适当方法。
下表是类适配器(ClassAdapter)和对象适配器(ObjectAdapter)的详细不同:

类适配器(ClassAdapter)对象适配器(ObjectAdapter)
基于继承概念利用对象合成
只能应用在适配者是接口,不能利用它子类的接口,当类适配器建立时,它就静态地与适配者关联可以应用在适配者是接口和它的所有子类
因为适配器是作为适配者的子类,所以适配器可能会重载适配者的一些行为。
注意:在JAVA中,子类不能重载父类中声明为final的方法。不能重载适配者的方法。
注意:字面上,不能重栽只是因为没有继承。但是适配器提供包装方法可以按需要改变行为。
客户类对适配者中声明为public的接口是可见的,客户类和适配者是完全不关联的,只有适配器才能感知适配者接口。
在JAVA应用程序中:
适用于期待的接口是JAVA接口的形式,而不是抽象地或具体地类的形式。这是因为
JAVA编程语言只允许单继承。因此,类适配器设计成适配者的子类。在JAVA应用程序中:
适用于当客户对象期望的接口是抽象类的形式,同时也可以应用于期望接口是Java接口的形式。


例子:
让我们建立一个验证给定客户地址的应用。这个应用是作为大的客户数据管理应用的一部分。
让我们定义一个Customer类:
Customer


Figure20.1:CustomerClass
Listing20.1:CustomerClass
  1. classCustomer{
  2. publicstaticfinalStringUS="US";
  3. publicstaticfinalStringCANADA="Canada";
  4. privateStringaddress;
  5. privateStringname;
  6. privateStringzip,state,type;
  7. publicbooleanisValidAddress(){
  8. }
  9. publicCustomer(Stringinp_name,Stringinp_address,
  10. Stringinp_zip,Stringinp_state,
  11. Stringinp_type){
  12. name=inp_name;
  13. address=inp_address;
  14. zip=inp_zip;
  15. state=inp_state;
  16. type=inp_type;
  17. }
  18. }//endofclass

不同的客户对象创建Customer对象并调用(invoke)isValidAddress方法验证客户地址的有效性。为了验证客户地址的有效性,Customer类期望利用一个地址验证类(addressvalidatorclass),这个验证类提供了在接口AddressValidator中声明的接口。
Listing20.2:AddressValidatorasanInterface
  1. publicinterfaceAddressValidator{
  2. publicbooleanisValidAddress(Stringinp_address,
  3. Stringinp_zip,Stringinp_state);
  4. }//endofclass

让我们定义一个USAddress的验证类,来验证给定的U.S地址。
Listing20.3:USAddressClass
  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()<5)
  7. returnfalse;
  8. if(inp_zip.trim().length()>10)
  9. returnfalse;
  10. if(inp_state.trim().length()!=2)
  11. returnfalse;
  12. returntrue;
  13. }
  14. }//endofclass

USAddress类实现AddressValidator接口,因此Customer对象使用USAddress实例作为验证客户地址过程的一部分是没有任何问题的。
Listing20.4:CustomerClassUsingtheUSAddressClass
  1. classCustomer{
  2. publicbooleanisValidAddress(){
  3. //getanappropriateaddressvalidator
  4. AddressValidatorvalidator=getValidator(type);
  5. //Polymorphiccalltovalidatetheaddress
  6. returnvalidator.isValidAddress(address,zip,state);
  7. }
  8. privateAddressValidatorgetValidator(StringcustType){
  9. AddressValidatorvalidator=null;
  10. if(custType.equals(Customer.US)){
  11. validator=newUSAddress();
  12. }
  13. returnvalidator;
  14. }
  15. }//endofclass


Figure20.2:Customer/USAddressValidator?ClassAssociation
但是当验证来自加拿大的客户时,就要对应用进行改进。这需要一个验证加拿大客户地址的验证类。让我们假设已经存在一个用来验证加拿大客户地址的使用工具类CAAddress,。
从下面的CAAdress类的实现,可以发现CAAdress提供了客户类Customer类所需要的验证服务。但是它所提供的接口不用于客户类Customer所期望的。
Listing20.5:CAAdressClasswithIncompatibleInterface
  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. }//endofclass

CAAdress类提供了一个isValidCanadianAddr方法,但是Customer期望一个声明在AddressValidator接口中的isValidAddress方法。
接口的不兼容使得Customer对象利用现有的CAAdress类是困难的。一种意见是改变CAAdress类的接口,但是可能会有其他的应用正在使用CAAdress类的这种形式。改变CAAdress类接口会影响现在使用CAAdress类的客户。
应用适配器模式,类适配器CAAdressAdapter可以继承CAAdress类实现AddressValidator接口。

Figure20.3:ClassAdapterfortheCAAddressClass
Listing20.6:CAAddressAdapterasaClassAdapter
  1. publicclassCAAddressAdapterextendsCAAddress
  2. implementsAddressValidator{
  3. publicbooleanisValidAddress(Stringinp_address,
  4. Stringinp_zip,Stringinp_state){
  5. returnisValidCanadianAddr(inp_address,inp_zip,
  6. inp_state);
  7. }
  8. }//endofclass

因为适配器CAAdressAdapter实现了AddressValidator接口,客户端对象访问适配器CAAdressAdapter对象是没有任何问题的。当客户对象调用适配器实例的isValidAddress方法的时候,适配器在内部把调用传递给它继承的isValidCanadianAddr方法。
在Customer类内部,getValidator私有方法需要扩展,以至于它可以在验证加拿大客户的时候返回一个CAAdressAdapter实例。返回的对象是多态的,USAddress和CAAddressAdapter都实现了AddressValidator接口,所以不用改变。
Listing20.7:CustomerClassUsingtheCAAddressAdapterClass
  1. classCustomer{
  2. publicbooleanisValidAddress(){
  3. //getanappropriateaddressvalidator
  4. AddressValidatorvalidator=getValidator(type);
  5. //Polymorphiccalltovalidatetheaddress
  6. returnvalidator.isValidAddress(address,zip,state);
  7. }
  8. privateAddressValidatorgetValidator(StringcustType){
  9. AddressValidatorvalidator=null;
  10. if(custType.equals(Customer.US)){
  11. validator=newUSAddress();
  12. }
  13. if(type.equals(Customer.CANADA)){
  14. validator=newCAAddressAdapter();
  15. }
  16. returnvalidator;
  17. }
  18. }//endofclass

CAAddressAdapter设计和对AddressValidator(声明期望的接口)对象的多态调用使Customer可以利用接口不兼容CAAddress类提供的服务。
TheclassdiagraminFigure20.4showstheoverallclassassociation.

Figure20.4:AddressValidationApplication?UsingClassAdapter
ThesequencediagraminFigure20.5depictsthemessageflowwhentheCAAddressAdapterisdesignedasaclassadapter.

Figure20.5:AddressValidationMessageFlow?UsingClassAdapter
作为对象适配器的地址适配器
当讨论以类适配器来实现地址适配器时,我们说客户类期望的AddressValidator接口是Java接口形式。现在,让我们假设客户类期望AddressValidator接口是抽象类而不是java接口。因为适配器CAAdapter必须提供抽象类AddressValidatro中声明的接口,适配器必须是AddressValidator抽象类的子类、实现抽象方法。
  1. Listing20.8:AddressValidatorasanAbstractClass
  2. publicabstractclassAddressValidator{
  3. publicabstractbooleanisValidAddress(Stringinp_address,
  4. Stringinp_zip,Stringinp_state);
  5. }//endofclass
  6. Listing20.9:CAAddressAdapterClass
  7. classCAAddressAdapterextendsAddressValidator{
  8. publicCAAddressAdapter(CAAddressaddress){
  9. objCAAddress=address;
  10. }
  11. publicbooleanisValidAddress(Stringinp_address,
  12. Stringinp_zip,Stringinp_state){
  13. }
  14. }//endofclass

因为多继承在JAVA中不支持,现在适配器CAAddressAdapter不能继承现有的CAAddress类,它已经使用了唯一一次继承其他类的机会。
应用对象适配器模式,CAAddressAdapter可以包含一个适配者CAAddress的一个实例。当适配器第一次创建的时候,这个适配者的实例通过客户端传递给适配器。通常,适配者实例可以通过下面两种方式提供给包装它的适配器。
(1)对象适配器的客户端可以传递一个适配者的实例给适配器。这种方式在选择类的形式上有很大的灵活性,但是客户端感知了适配者或者适配过程。这种方法在适配器不但需要适配者对象行为而且需要特定状态时很适合。
(2)适配器可以自己创建适配者实例。这种方法相对来说缺乏灵活性。适用于适配器只需要适配者对象的行为而不需要适配者对象的特定状态的情况。

Figure20.6:ObjectAdapterfortheCAAddressClass
Listing20.10:CAAddressAdapterasanObjectAdapter
  1. classCAAddressAdapterextendsAddressValidator{
  2. privateCAAddressobjCAAddress;
  3. publicCAAddressAdapter(CAAddressaddress){
  4. objCAAddress=address;
  5. }
  6. publicbooleanisValidAddress(Stringinp_address,
  7. Stringinp_zip,Stringinp_state){
  8. returnobjCAAddress.isValidCanadianAddr(inp_address,
  9. inp_zip,inp_state);
  10. }
  11. }//endofclass

当客户对象调用CAAddressAdapter(adapter)上的isValidAddress方法时,适配器在内部调用CAAddress(adaptee)上的isValidCanadianAddr方法。
TheclassdiagraminFigure20.7showstheoverallclassassociationwhentheaddressadapterisdesignedasanobjectadapter.

Figure20.7:AddressValidationApplication?UsingObjectAdapter
从这个例子可以看出,适配器可以使Customer(client)类访问借口不兼容的CAAddress(adaptee)所提供的服务!
ThesequencediagraminFigure20.8showsthemessageflowwhentheadapterCAAddressAdapterisdesignedasanobjectadapter.

Figure20.8:AddressValidationMessageFlow?UsingObjectAdapter
附件为原文和代码:
分享到:
评论

相关推荐

    设计模式之适配器模式(Adapter Pattern)

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

    Head First 设计模式 (七) 适配器模式(Adapter pattern) C++实现

    Head First 设计模式 (七) 适配器模式(Adapter pattern) C++实现

    Java24种设计模式,Java24种设计模式,24种设计模式,学会了这24种设计模式,可以打遍天下无敌手,设计模式非常重要

    8、适配器模式ADAPTER PATTERN 9、模板方法模式TEMPLATE METHOD PATTERN 10、建造者模式BUILDER PATTERN 11、桥梁模式BRIDGE PATTERN 12、命令模式COMMAND PATTERN 13、装饰模式DECORATOR PATTERN 14、迭代器模式...

    设计模式:结构型-适配器模式

    适配器模式(Adapter Pattern) 是作为两个不兼容接口之间的桥梁, 这种类型的设计模式属于结构型模式。 一些书籍也称适配器模式为缺省适配器模式(Default Adapter Pattern) 。 适配器模式主要分 为三类: 类...

    设计模式 之 “适配器模式[Adapter Pattern]”

    NULL 博文链接:https://lym6520.iteye.com/blog/713094

    适配器模式

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

    .NET设计模式(8):适配器模式(AdapterPattern)

    .NET设计模式(8):适配器模式(AdapterPattern)

    java设计模式之适配器模式

    java设计模式之适配器模式,希望对大家有所帮助。

    设计模式_适配器模式.zip

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

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

    用c++方法实现AdapterPattern模式

    Python设计模式之适配器模式原理与用法详解

    本文实例讲述了Python设计模式之...适配器模式(Adapter Pattern):将一个类的接口转换成为客户希望的另外一个接口.Adapter Pattern使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 应用场景:系统数据和

    C#版 24种设计模式

    适配器模式(Adapter Pattern) 提供者模式(Provider Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 原型模式(Prototype Pattern) 责任链模式(Chain of Responsibility Pattern) 中介者模式...

    用Java实现23种设计模式

    适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 过滤器模式(Filter、Criteria Pattern) 组合模式(Composite Pattern) 装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式...

    C#设计模式_设计模式_C#_

    适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 装饰模式(Decorator Pattern) 9. 组合模式(Composite Pattern) 10. 外观模式(Facade Pattern) 11. 享元模式(Flyweight Pattern) 12. 代理模式...

    Java设计模式,并加上个人理解

    7. 适配器模式 (Adapter Pattern) 8. 模板方法模式 (Template Pattern) 9. 建造者模式 (Builder Pattern) 10. 原型模式 (Prototype Pattern) 11. 组合模式 (Composite Pattern) 12. 装饰者模式 ...

    C#设计模式(23种设计模式)

    适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 装饰模式(Decorator Pattern) 9. 组合模式(Composite Pattern) 10. 外观模式(Facade Pattern) 11. 享元模式(Flyweight Pattern) 12. ...

    设计模式PPT

     适配器模式(Adapter Pattern)  桥接模式(Bridge Pattern)  组合模式(Composite Pattern)  装饰者模式(Decorator Pattern)  外观模式(Facade Pattern)  享元模式(Flyweight Pattern)  ...

    设计模式代码——c#

    6. 适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 装饰模式(Decorator Pattern) 9. 组合模式(Composite Pattern) 10. 外观模式(Facade Pattern) 11. 享元模式(Flyweight Pattern) 12....

    23种设计模式 (创建型,结构型,行为型)

    适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 装饰模式(Decorator Pattern) 9. 组合模式(Composite Pattern) 10. 外观模式(Facade Pattern) 11. 享元模式(Flyweight Pattern) 12. ...

Global site tag (gtag.js) - Google Analytics