适配器模式

438 阅读3分钟

定义

将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

适配器模式,又叫变压模式或包装模式,但包装模式不仅限于适配器模式。

类图

类适配器通用类图

Target目标角色:该角色定义把其他类转化为何种接口

Adaptee源角色:想把谁转化为目标角色,谁就是源角色,是已经存在的,运行良好的接口。

Adaptor适配器角色:适配器模式的核心角色,其他两个角色都是已经存在的,只有这个角色需要新创建,将源角色转化为目标角色。通过类继承或类关联的方式。

通用代码

目标角色

public interface Target{
    public String request();
}

目标角色的实现类

public class ConcreteTarget implements Target{
    
    public String request(){
        return "";
    }
    
}

源角色

public class Adaptee{
    public String doSomething(){
        System.out.println("do something");
        return "";
    }
}

适配器角色

public class Adaptor extends Adaptee implements Target{
    public String request(){
        return super.doSomething();
    }
}

场景类

public class Client{
    public static void main(String[] args){
        //原有逻辑
        Target target = new ConcreteTarget();
        target.request();
        //增加适配器后的逻辑
        target = new Adaptor();
        target.request();
    }
}

应用

优点

  • 可以让两个没有任何关系的类在一起运行,只要适配器角色可以搞定。
  • 增加了类的透明性(访问的是Target类,而实际调用源角色类,对高层次透明)
  • 提高了类的复用度(源角色可以正常运行,也可以在目标角色充当新左右)
  • 灵活性好(不想用可以删掉适配器类即可,可随时卸载)

场景

有动机修改已经使用的接口,适配器模式比较适合。比如系统扩展了,要新建一个类,但是类不适用系统接口,则可以使用适配器。

注意

不是为了解决开发阶段的问题,而是解决服役中的项目问题。不能一开始就使用 适配器模式。

对象适配器

刚刚上面通过继承来实现适配的,称为类适配器。还可以通过对象层次的关联关系进行适配,称为对象适配器。

类图:

适配器通用类图

通用代码

目标角色

public interface Target{
    public String request();
    
    public String response();
}

目标角色的实现类

public class ConcreteTarget implements Target{
    
    public String request(){
        return "";
    }
    
      public String response(){
        return "";
    }
    
}

源角色

public class Adaptee1{
    public String doSomething(){
        System.out.println("do something");
        return "";
    }
}

public class Adaptee2{
    public String doOtherthing(){
        System.out.println("do otherthing");
        return "";
    }
}

适配器角色

public class Adaptor implements Target{
    
    private Adaptee1 adaptee1;
    
    private Adaptee2 adaptee2;
    
    public Adaptor(Adaptee1 adaptee1,Adaptee2 adaptee2){
        this.adaptee1 = adaptee1;
        this.adaptee2 = adaptee2;
    }
    
    public String request(){
        return this.adaptee1.doSomething();
    }
    
     public String response(){
        return this.adaptee2.doOtherthing();
    }
}

场景类

public class Client{
    public static void main(String[] args){
        //原有逻辑
        Target target = new ConcreteTarget();
        target.request();
        target.response();
        //增加适配器后的逻辑
        Adaptee1 adaptee1 = new Adaptee1();
          Adaptee2 adaptee2 = new Adaptee2();
        target = new Adaptor(adaptee1,adaptee2);
        target.request();
        target.response();
    }
}

JDK使用的适配器了解

DatagramSocketAdaptor、SocketAdaptor

public class DatagramSocketAdaptor extends DatagramSocket{

    // The channel being adapted
    private final DatagramChannelImpl dc;

    // Timeout "option" value for receives
    private volatile int timeout = 0;

     public static DatagramSocket create(DatagramChannelImpl dc) {
        try {
            return new DatagramSocketAdaptor(dc);
        } catch (IOException x) {
            throw new Error(x);
        }
    }
    ...    
}
public class SocketAdaptor extends Socket{

    // The channel being adapted
    private final SocketChannelImpl sc;

    // Timeout "option" value for reads
    private volatile int timeout = 0;

    public static Socket create(SocketChannelImpl sc) {
        try {
            return new SocketAdaptor(sc);
        } catch (SocketException e) {
            throw new InternalError("Should not reach here");
        }
    }
    ...
}

两个类注释的开头都写着,使得这种socket 通道看起来和这种socket一样。即对 通道进行对应的socket适配。使用对象适配。