从下面的CAAdress类的实现,可以发现CAAdress提供了客户类Customer类所需要的验证服务。但是它所提供的接口不用于客户类Customer所期望的。
Listing 20.5: CAAdress Class with Incompatible Interface
- class 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 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
- 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 20.7: 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 validator.isValidAddress(address, zip, state);
- }
- private AddressValidator getValidator(String custType) {
- AddressValidator validator = null;
- if (custType.equals(Customer.US)) {
- validator = new USAddress();
- }
- if (type.equals(Customer.CANADA)) {
- validator = new CAAddressAdapter();
- }
- return validator;
- }
- }//end of class
CAAddressAdapter设计和对AddressValidator(声明期望的接口)对象的多态调用使Customer可以利用接口不兼容CAAddress类提供的服务。

Figure 20.4: Address Validation Application?Using Class Adapter

Figure 20.5: Address Validation Message Flow?Using Class Adapter
作为对象适配器的地址适配器
当讨论以类适配器来实现地址适配器时,我们说客户类期望的AddressValidator接口是Java接口形式。现在,让我们假设客户类期望AddressValidator接口是抽象类而不是java接口。因为适配器CAAdapter必须提供抽象类AddressValidatro中声明的接口,适配器必须是AddressValidator抽象类的子类、实现抽象方法。
- Listing 20.8: 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 20.9: 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的一个实例。当适配器第一次创建的时候,这个适配者的实例通过客户端传递给适配器。通常,适配者实例可以通过下面两种方式提供给包装它的适配器。
(1) 对象适配器的客户端可以传递一个适配者的实例给适配器。这种方式在选择类的形式上有很大的灵活性,但是客户端感知了适配者或者适配过程。这种方法在适配器不但需要适配者对象行为而且需要特定状态时很适合。
(2) 适配器可以自己创建适配者实例。这种方法相对来说缺乏灵活性。适用于适配器只需要适配者对象的行为而不需要适配者对象的特定状态的情况。

Figure 20.6: Object Adapter for the CAAddress Class
Listing 20.10: 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 objCAAddress.isValidCanadianAddr(inp_address,
- inp_zip, inp_state);
- }
- }//end of class
当客户对象调用CAAddressAdapter(adapter)上的isValidAddress方法时, 适配器在内部调用CAAddress(adaptee)上的isValidCanadianAddr方法。

Figure 20.7: Address Validation Application?Using Object Adapter
从这个例子可以看出,适配器可以使Customer(client)类访问借口不兼容的CAAddress(adaptee)所提供的服务!

Figure 20.8: Address Validation Message Flow?Using Object Adapter