设计模式--class adapter object adapter

通常,客户类是通过另一个类提供的方法访问另一个类的服务。有时,现有的类可以提供给客户类的功能需要,但是它所提供的方法不一定是客户类所期望的。这是由于现有的方法太详细或者缺乏详细或方法的名称与客户类所查找的不同等诸多不同原因导致的。

在这种情况下,现有的方法需要转化为客户类期望的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类所提供的功能。适 配器模式可以完成这样的转化。适配器模式建议定义一个包装类,包装有不兼容方法的对象。这个包装类指的就是适配器(Adapter),它包装的对象就是适 配者(Adaptee)。适配器提供客户类需要的方法,适配器接口的实现是把客户类的请求转化为对适配者的相应接口的调用。换句话说:当客户类调用适配器 的方法时,在适配器类的内部调用适配者类的方法,这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的 类可以一起工作。

在上面讨论的接口:
(1)不是指在JAVA编程语言中接口的概念,虽然类的接口可以通过JAVA借扩来定义。
(2)不是指由窗体和GUI控件所组成的GUI应用程序的用户接口。
(3)而是指类所暴露的,被其他类调用的编程接口,

适配器总体上可以分为两类:类适配器(Class Adapter)VS对象适配器(Object Adapter)

类适配器:

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

对象适配器:

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

1 类适配器

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

让我们定义一个Customer类:
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) {
        this.name = inp_name;
        this.address = inp_address;
        this.zip = inp_zip;
        this.state = inp_state;
        this.type = inp_type;
    }
}//end of class

不同的客户对象创建Customer对象并调用isValidAddress方法验证客户地址的有效性。为了验证客户地址的有效 性,Customer类期望利用一个地址验证类(address validator class),这个验证类提供了在接口AddressValidator中声明的接口。


public interface AddressValidator {
    public boolean isValidAddress(String inp_address,
        String inp_zip, String inp_state);
}//end of interface

让我们定义一个USAddress的验证类,来验证给定的U.S地址:
class 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() < 5)
            return false;
        if (inp_zip.trim().length() > 10)
            return false;
        if (inp_state.trim().length() != 2)
            return false;
        return true;
    }
}//end of class

USAddress类实现AddressValidator接口,因此Customer对象使用USAddress实例作为验证客户地址过程的一部分是没有任何问题的:
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();
        }
        return validator;
    }
}//end of class

但是当验证来自加拿大的客户时,就要对应用进行改进。这需要一个验证加拿大客户地址的验证类。让我们假设已经存在一个用来验证加拿大客户地址的使用工具类CAAddress。

从下面的CAAdress类的实现,可以发现CAAdress提供了客户类Customer类所需要的验证服务。但是它所提供的接口不用于客户类Customer所期望的:
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接口:
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接口,所以不用改变。

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

2 对象适配器

当讨论以类适配器来实现地址适配器时,我们说客户类期望的AddressValidator接口是Java接口形式。现在,让我们假设客户类期望 AddressValidator接口是抽象类而不是java接口。因为适配器CAAdapter必须提供抽象类 AddressValidatro中声明的接口,适配器必须是AddressValidator抽象类的子类、实现抽象方法。

public abstract class AddressValidator {
    public abstract boolean isValidAddress(String inp_address,
        String inp_zip, String inp_state);
}//end of 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) 适配器可以自己创建适配者实例。这种方法相对来说缺乏灵活性。适用于适配器只需要适配者对象的行为而不需要适配者对象的特定状态的情况。

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方法。

从这个例子可以看出,适配器可以使Customer(client)类访问接口不兼容的CAAddress(adaptee)所提供的服务!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值