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

一、适配器模式的定义

将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

设计模式——适配器模式(Adapter Pattern)_第1张图片

对象适配器的类图:

设计模式——适配器模式(Adapter Pattern)_第2张图片

Target

public interface ITarget {
    public void request();
}

目标接口,与客户对接。

Adapter

public class Adapter implements ITarget {
    // 持有一个Adaptee对象
    private Adaptee adapetee;
    public Adapter(Adaptee adaptee) {
        this.adapetee = adaptee;
    }
    public void request() {
        adaptee.requestOfAdaptee();
    }
}

适配器,他与被适配者组合。适配器模式中并不是说只能适配一个被适配者,也可以将多个被适配者组合起来一起形成一个客户所需要的目标接口。

Adaptee

public class Adaptee {
    public void requestOfAdaptee() {
        System.out.println("requestOfAdaptee run...")
    }
}

被适配者,真正的实现者,所有的请求都委托给adaptee。

client

客户只看到目标接口Target,不知道后面的具体实现,因而将客户与实现进行解耦。

public class Client {
    public static void main(String[] args) {
        // 为用户准备ITarget
        Adaptee adaptee = new Adaptee();
        ITarget target = new Adapter(adaptee);

        // 客户调用Itarget的接口
        target.request();
    }
}

类适配器类图——多继承实现

设计模式——适配器模式(Adapter Pattern)_第3张图片

在这种类适配其中,使用多继承的方式实现,因而不适合java这种不支持多继承的语言。适配器(Adapter)继承了Target类和Adaptee类,因此可以很容易在重写的request()方法中,调用requestOfAdaptee()方法,从而实现适配。

类适配器类图——非多继承实现

设计模式——适配器模式(Adapter Pattern)_第4张图片
非多继承实现时,Adapter实现Target定义的接口,并单继承Adaptee类,因此可以使用Adaptee中的requestOfAdaptee方法来实现request接口。

二、对象适配器vs类适配器

  • 对象适配器使用组合,因此可以适配该类的任何子类,更加灵活,扩展性也更好。
  • 对象适配器中加入的任何行为,都能搭配被适配者的子类工作。
  • 类适配器使用继承,因此只能适配某一个特定的被适配类。
  • 类适配器可以使用覆盖的方式修改被适配者的行为,而不用直接修改被适配者的代码。

总结:强烈建议使用对象适配器,这也是面向对象编程的一个原则之一:多使用组合,而不是继承。先不说类适配器固有的缺点,就其优点,个人觉得其实也有不妥:

  • 适配器和被适配器不应该是“is-a”的关系,而应该是“has-a”的关系。
  • 适配器中通过覆盖的方式修改被适配者的行为不妥,因为适配器中不应该有太多的具体实现,而更多的是接口转换(比如参数转化等非核心业务逻辑的胶水代码),具体实现应该是在被适配者类中实现。如果要改变被适配类的行为,可以使用被适配者的子类去覆盖,然后将适配器的组合对象指向这个子类就行了。

三、适配器模式的优缺点

优点

  • 通过适配器转换接口,将不兼容接口变为兼容,将客户与实现者解耦。适配器将改变部分封装起来,客户不必为了对应不用的接口而每次都进行修改。
  • 使用对象组合来使用被适配器的方法,因此该适配器也能使用被适配者的任何子类。
  • 适配器模式将客户与接口对接起来,而不是与实现对接,所以可以使用多个适配器,来适配不同的接口。
  • 灵活性和扩展性都非常好,符合开闭原则。

缺点

  • 对象适配器,使用子类的方式来置换被适配者的行为,使得代码实现更加复杂。

四、适应场景

  • 想使用某个已有类,无法直接使用该类的接口。
  • 想将一个复用,供多个不同的使用者调用,可以实现一些适配器来适配不同客户。

你可能感兴趣的:(设计模式)