無為

          無為則可為,無為則至深!

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            190 Posts :: 291 Stories :: 258 Comments :: 0 Trackbacks
          適配器模式(Adapter Pattern)

          說明:


              通常,客戶類(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類:
          Customer 


          Figure 20.1: Customer Class 
          Listing 20.1: Customer Class 
          1. class Customer { 
          2.   public static final String US = "US"
          3.   public static final String CANADA = "Canada"
          4.   private String address; 
          5.   private String name; 
          6.   private String zip, state, type; 
          7.   public boolean isValidAddress() { 
          8.           … 
          9.           … 
          10.   } 
          11.   public Customer(String inp_name, String inp_address, 
          12.                   String inp_zip, String inp_state, 
          13.                   String inp_type) { 
          14.     name = inp_name; 
          15.     address = inp_address; 
          16.     zip = inp_zip; 
          17.     state = inp_state; 
          18.     type = inp_type; 
          19.   } 
          20. }//end of class 

              不同的客戶對象創建Customer對象并調用(invoke)isValidAddress方法驗證客戶地址的有效性。為了驗證客戶地址的有效性,Customer類期望利用一個地址驗證類(address validator class),這個驗證類提供了在接口AddressValidator中聲明的接口。
          Listing 20.2: AddressValidator as an Interface 
          1. public interface AddressValidator { 
          2.   public boolean isValidAddress(String inp_address, 
          3.      String inp_zip, String inp_state); 
          4. }//end of class 

             讓我們定義一個USAddress的驗證類,來驗證給定的U.S地址。
          Listing 20.3: USAddress Class 
          1. class USAddress implements AddressValidator { 
          2.   public boolean isValidAddress(String inp_address, 
          3.      String inp_zip, String inp_state) { 
          4.    if (inp_address.trim().length() < 10) 
          5.      return false
          6.    if (inp_zip.trim().length() < 5) 
          7.      return false
          8.    if (inp_zip.trim().length() > 10) 
          9.      return false
          10.    if (inp_state.trim().length() != 2) 
          11.      return false
          12.    return true
          13.   } 
          14. }//end of class 

              USAddress類實現AddressValidator接口,因此Customer對象使用USAddress實例作為驗證客戶地址過程的一部分是沒有任何問題的。
          Listing 20.4: Customer Class Using the USAddress Class 
          1. class Customer { 
          2.           … 
          3.           … 
          4.  public boolean isValidAddress() { 
          5.    //get an appropriate address validator 
          6.    AddressValidator validator = getValidator(type); 
          7.    //Polymorphic call to validate the address 
          8.    return validator.isValidAddress(address, zip, state); 
          9.  } 
          10.  private AddressValidator getValidator(String custType) { 
          11.    AddressValidator validator = null
          12.    if (custType.equals(Customer.US)) { 
          13.      validator = new USAddress(); 
          14.    } 
          15.    return validator; 
          16.  } 
          17. }//end of class 
           

          Figure 20.2: Customer/USAddress Validator?Class Association 
              但是當驗證來自加拿大的客戶時,就要對應用進行改進。這需要一個驗證加拿大客戶地址的驗證類。讓我們假設已經存在一個用來驗證加拿大客戶地址的使用工具類CAAddress,。
          從下面的CAAdress類的實現,可以發現CAAdress提供了客戶類Customer類所需要的驗證服務。但是它所提供的接口不用于客戶類Customer所期望的。
          Listing 20.5: CAAdress Class with Incompatible Interface 
          1. class CAAddress { 
          2.   public boolean isValidCanadianAddr(String inp_address, 
          3.      String inp_pcode, String inp_prvnc) { 
          4.    if (inp_address.trim().length() < 15) 
          5.      return false
          6.    if (inp_pcode.trim().length() != 6) 
          7.      return false
          8.    if (inp_prvnc.trim().length() < 6) 
          9.      return false
          10.    return true
          11.   } 
          12. }//end of class 

              CAAdress類提供了一個isValidCanadianAddr方法,但是Customer期望一個聲明在AddressValidator接口中的isValidAddress方法。
          接口的不兼容使得Customer對象利用現有的CAAdress類是困難的。一種意見是改變CAAdress類的接口,但是可能會有其他的應用正在使用CAAdress類的這種形式。改變CAAdress類接口會影響現在使用CAAdress類的客戶。
          應用適配器模式,類適配器CAAdressAdapter可以繼承CAAdress類實現AddressValidator接口。
           
          Figure 20.3: Class Adapter for the CAAddress Class 
          Listing 20.6: CAAddressAdapter as a Class Adapter 
          1. public class CAAddressAdapter extends CAAddress 
          2.   implements AddressValidator { 
          3.   public boolean isValidAddress(String inp_address, 
          4.      String inp_zip, String inp_state) { 
          5.     return isValidCanadianAddr(inp_address, inp_zip, 
          6.            inp_state); 
          7.   } 
          8. }//end of class 

              因為適配器CAAdressAdapter實現了AddressValidator接口,客戶端對象訪問適配器CAAdressAdapter對象是沒有任何問題的。當客戶對象調用適配器實例的isValidAddress方法的時候,適配器在內部把調用傳遞給它繼承的isValidCanadianAddr方法。
          在Customer類內部,getValidator私有方法需要擴展,以至于它可以在驗證加拿大客戶的時候返回一個CAAdressAdapter實例。返回的對象是多態的,USAddress和CAAddressAdapter都實現了AddressValidator接口,所以不用改變。
          Listing 20.7: Customer Class Using the CAAddressAdapter Class 
          1. class Customer { 
          2.           … 
          3.           … 
          4.   public boolean isValidAddress() { 
          5.     //get an appropriate address validator 
          6.     AddressValidator validator = getValidator(type); 
          7.     //Polymorphic call to validate the address 
          8.     return validator.isValidAddress(address, zip, state); 
          9.   } 
          10.   private AddressValidator getValidator(String custType) { 
          11.     AddressValidator validator = null
          12.     if (custType.equals(Customer.US)) { 
          13.       validator = new USAddress(); 
          14.     } 
          15.     if (type.equals(Customer.CANADA)) { 
          16.       validator = new CAAddressAdapter(); 
          17.     } 
          18.     return validator; 
          19.   } 
          20. }//end of class 

              CAAddressAdapter設計和對AddressValidator(聲明期望的接口)對象的多態調用使Customer可以利用接口不兼容CAAddress類提供的服務。
          The class diagram in Figure 20.4 shows the overall class association.
           
          Figure 20.4: Address Validation Application?Using Class Adapter 
          The sequence diagram in Figure 20.5 depicts the message flow when the CAAddressAdapter is designed as a class adapter.
           
          Figure 20.5: Address Validation Message Flow?Using Class Adapter 
          作為對象適配器的地址適配器
          當討論以類適配器來實現地址適配器時,我們說客戶類期望的AddressValidator接口是Java接口形式。現在,讓我們假設客戶類期望AddressValidator接口是抽象類而不是java接口。因為適配器CAAdapter必須提供抽象類AddressValidatro中聲明的接口,適配器必須是AddressValidator抽象類的子類、實現抽象方法。
          1. Listing 20.8: AddressValidator as an Abstract Class 
          2. public abstract class AddressValidator { 
          3.   public abstract boolean isValidAddress(String inp_address, 
          4.      String inp_zip, String inp_state); 
          5. }//end of class 
          6. Listing 20.9: CAAddressAdapter Class 
          7. class CAAddressAdapter extends AddressValidator { 
          8.           … 
          9.           … 
          10.   public CAAddressAdapter(CAAddress address) { 
          11.     objCAAddress = address; 
          12.   } 
          13.   public boolean isValidAddress(String inp_address, 
          14.      String inp_zip, String inp_state) { 
          15.           … 
          16.           … 
          17.   } 
          18. }//end of class 

              因為多繼承在JAVA中不支持,現在適配器CAAddressAdapter不能繼承現有的CAAddress類,它已經使用了唯一一次繼承其他類的機會。
          應用對象適配器模式,CAAddressAdapter可以包含一個適配者CAAddress的一個實例。當適配器第一次創建的時候,這個適配者的實例通過客戶端傳遞給適配器。通常,適配者實例可以通過下面兩種方式提供給包裝它的適配器。
          (1)    對象適配器的客戶端可以傳遞一個適配者的實例給適配器。這種方式在選擇類的形式上有很大的靈活性,但是客戶端感知了適配者或者適配過程。這種方法在適配器不但需要適配者對象行為而且需要特定狀態時很適合。
          (2)    適配器可以自己創建適配者實例。這種方法相對來說缺乏靈活性。適用于適配器只需要適配者對象的行為而不需要適配者對象的特定狀態的情況。
           
          Figure 20.6: Object Adapter for the CAAddress Class 
          Listing 20.10: CAAddressAdapter as an Object Adapter 
          1. class CAAddressAdapter extends AddressValidator { 
          2.   private CAAddress objCAAddress; 
          3.   public CAAddressAdapter(CAAddress address) { 
          4.     objCAAddress = address; 
          5.   } 
          6.   public boolean isValidAddress(String inp_address, 
          7.      String inp_zip, String inp_state) { 
          8.     return objCAAddress.isValidCanadianAddr(inp_address, 
          9.            inp_zip, inp_state); 
          10.   } 
          11. }//end of class 

              當客戶對象調用CAAddressAdapter(adapter)上的isValidAddress方法時, 適配器在內部調用CAAddress(adaptee)上的isValidCanadianAddr方法。
          The class diagram in Figure 20.7 shows the overall class association when the address adapter is designed as an object adapter.
           
          Figure 20.7: Address Validation Application?Using Object Adapter 
          從這個例子可以看出,適配器可以使Customer(client)類訪問借口不兼容的CAAddress(adaptee)所提供的服務!
          The sequence diagram in Figure 20.8 shows the message flow when the adapter CAAddressAdapter is designed as an object adapter. 
           
          Figure 20.8: Address Validation Message Flow?Using Object Adapter 
          附件為原文和代碼:
          [img]附件:24.rar(17K) 附件:Chapter_20.doc(267K) 

          凡是有該標志的文章,都是該blog博主Caoer(草兒)原創,凡是索引、收藏
          、轉載請注明來處和原文作者。非常感謝。

          posted on 2006-02-16 09:06 草兒 閱讀(348) 評論(0)  編輯  收藏 所屬分類: 設計模式
          主站蜘蛛池模板: 房产| 韩城市| 论坛| 土默特右旗| 绥芬河市| 高密市| 固镇县| 咸丰县| 大城县| 洪雅县| 武乡县| 晴隆县| 怀柔区| 塔河县| 苏尼特左旗| 潞西市| 罗定市| 信阳市| 夏津县| 天镇县| 石家庄市| 印江| 壤塘县| 莆田市| 馆陶县| 大连市| 梁河县| 通化县| 大港区| 安宁市| 柘城县| 北京市| 南康市| 乐至县| 孝义市| 永福县| 积石山| 开鲁县| 丰镇市| 潍坊市| 阳江市|