熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java設計模式之Adapter模式

2022-06-13   來源: Java高級技術 

  通常客戶類(clients of class)通過類的接口訪問它提供的服務有時現有的類(existing class)可以提供客戶類的功能需要但是它所提供的接口不一定是客戶類所期望的這是由於現有的接口太詳細或者缺乏詳細或接口的名稱與客戶類所查找的不同等諸多不同原因導致的

  在這種情況下現有的接口需要轉化(convert)為客戶類期望的接口這樣保證了對現有類的重用如果不進行這樣的轉化客戶類就不能利用現有類所提供的功能適配器模式(Adapter Pattern)可以完成這樣的轉化適配器模式建議定義一個包裝類包裝有不兼容接口的對象這個包裝類指的就是適配器(Adapter)它包裝的對象就是適配者(Adaptee)適配器提供客戶類需要的接口適配器接口的實現是把客戶類的請求轉化為對適配者的相應接口的調用換句話說當客戶類調用適配器的方法時在適配器類的內部調用適配者類的方法這個過程對客戶類是透明的客戶類並不直接訪問適配者類因此適配器可以使由於接口不兼容而不能交互的類可以一起工作(work together)

  在上面討論的接口

  ()     不是指在JAVA編程語言中接口的概念雖然類的接口可以通過JAVA借擴來定義

  ()     不是指由窗體和GUI控件所組成的GUI應用程序的用戶接口

  ()     而是指類所暴露的被其他類調用的編程接口

  類適配器(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 : Customer Class

  Listing : Customer Class

  class 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中聲明的接口

  Listing : AddressValidator as an Interface

  public interface AddressValidator {

  public boolean isValidAddress(String inp_address

  String inp_zip String inp_state);

  }//end of class

  讓我們定義一個USAddress的驗證類來驗證給定的US地址

  Listing : USAddress Class

  class USAddress implements AddressValidator {

  public boolean isValidAddress(String inp_address

  String inp_zip String inp_state) {

  if (inp_addresstrim()length() < )

  return false;

  if (inp_ziptrim()length() < )

  return false;

  if (inp_ziptrim()length() > )

  return false;

  if (inp_statetrim()length() != )

  return false;

  return true;

  }

  }//end of class

  USAddress類實現AddressValidator接口因此Customer對象使用USAddress實例作為驗證客戶地址過程的一部分是沒有任何問題的

  Listing : Customer Class Using the USAddress Class

  class Customer {

  …

  …

  public boolean isValidAddress() {

  //get an appropriate address validator

  AddressValidator validator = getValidator(type);

  //Polymorphic call to validate the address

  return validatorisValidAddress(address zip state);

  }

  private AddressValidator getValidator(String custType) {

  AddressValidator validator = null;

  if (custTypeequals(CustomerUS)) {

  validator = new USAddress();

  }

  return validator;

  }

  }//end of class

  

  Figure : Customer/USAddress Validator?Class Association

  但是當驗證來自加拿大的客戶時就要對應用進行改進這需要一個驗證加拿大客戶地址的驗證類讓我們假設已經存在一個用來驗證加拿大客戶地址的使用工具類CAAddress

  從下面的CAAdress類的實現可以發現CAAdress提供了客戶類Customer類所需要的驗證服務但是它所提供的接口不用於客戶類Customer所期望的從下面的CAAdress類的實現可以發現CAAdress提供了客戶類Customer類所需要的驗證服務但是它所提供的接口不用於客戶類Customer所期望的

  Listing : CAAdress Class with Incompatible Interface

  class CAAddress {

  public boolean isValidCanadianAddr(String inp_address

  String inp_pcode String inp_prvnc) {

  if (inp_addresstrim()length() < )

  return false;

  if (inp_pcodetrim()length() != )

  return false;

  if (inp_prvnctrim()length() < )

  return false;

  return true;

  }

  }//end of class

  CAAdress類提供了一個isValidCanadianAddr方法但是Customer期望一個聲明在AddressValidator接口中的isValidAddress方法

  接口的不兼容使得Customer對象利用現有的CAAdress類是困難的一種意見是改變CAAdress類的接口但是可能會有其他的應用正在使用CAAdress類的這種形式改變CAAdress類接口會影響現在使用CAAdress類的客戶

  應用適配器模式類適配器CAAdressAdapter可以繼承CAAdress類實現AddressValidator接口

  

  Figure : Class Adapter for the CAAddress Class

  Listing : CAAddressAdapter as a Class Adapter

  public 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接口所以不用改變

  Listing : Customer Class Using the CAAddressAdapter Class

  class Customer {

  …

  …

  public boolean isValidAddress() {

  //get an appropriate address validator

  AddressValidator validator = getValidator(type);

  //Polymorphic call to validate the address

  return validatorisValidAddress(address zip state);

  }

  private AddressValidator getValidator(String custType) {

  AddressValidator validator = null;

  if (custTypeequals(CustomerUS)) {

  validator = new USAddress();

  }

  if (typeequals(CustomerCANADA)) {

  validator = new CAAddressAdapter();

  }

  return validator;

  }

  }//end of class

  CAAddressAdapter設計和對AddressValidator(聲明期望的接口)對象的多態調用使Customer可以利用接口不兼容CAAddress類提供的服務

  

  Figure : Address Validation Application?Using Class Adapter

  

  Figure : Address Validation Message Flow?Using Class Adapter

  作為對象適配器的地址適配器

  當討論以類適配器來實現地址適配器時我們說客戶類期望的AddressValidator接口是Java接口形式現在讓我們假設客戶類期望AddressValidator接口是抽象類而不是java接口因為適配器CAAdapter必須提供抽象類AddressValidatro中聲明的接口適配器必須是AddressValidator抽象類的子類實現抽象方法

  Listing : AddressValidator as an Abstract Class

  public abstract class AddressValidator {

  public abstract boolean isValidAddress(String inp_address

  String inp_zip String inp_state);

  }//end of class

  Listing : CAAddressAdapter Class

  class CAAddressAdapter extends AddressValidator {

  …

  …

  public CAAddressAdapter(CAAddress address) {

  objCAAddress = address;

  }

  public boolean isValidAddress(String inp_address

  String inp_zip String inp_state) {

  …

  …

  }

  }//end of class

  因為多繼承在JAVA中不支持現在適配器CAAddressAdapter不能繼承現有的CAAddress類它已經使用了唯一一次繼承其他類的機會

  應用對象適配器模式CAAddressAdapter可以包含一個適配者CAAddress的一個實例當適配器第一次創建的時候這個適配者的實例通過客戶端傳遞給適配器通常適配者實例可以通過下面兩種方式提供給包裝它的適配器

  ()     對象適配器的客戶端可以傳遞一個適配者的實例給適配器這種方式在選擇類的形式上有很大的靈活性但是客戶端感知了適配者或者適配過程這種方法在適配器不但需要適配者對象行為而且需要特定狀態時很適合

  ()     適配器可以自己創建適配者實例這種方法相對來說缺乏靈活性適用於適配器只需要適配者對象的行為而不需要適配者對象的特定狀態的情況

  

  Figure : Object Adapter for the CAAddress Class

  Listing : CAAddressAdapter as an Object Adapter

  class CAAddressAdapter extends AddressValidator {

  private CAAddress objCAAddress;

  public CAAddressAdapter(CAAddress address) {

  objCAAddress = address;

  }

  public boolean isValidAddress(String inp_address

  String inp_zip String inp_state) {

  return objCAAddressisValidCanadianAddr(inp_address

  inp_zip inp_state);

  }

  }//end of class

  當客戶對象調用CAAddressAdapter(adapter)上的isValidAddress方法時 適配器在內部調用CAAddress(adaptee)上的isValidCanadianAddr方法

  

  Figure : Address Validation Application?Using Object Adapter

  從這個例子可以看出適配器可以使Customer(client)類訪問借口不兼容的CAAddress(adaptee)所提供的服務!

  


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27273.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.