《设计模式》-- 适配器模式

适配器模式

认识

适配器模式是将一个类的接口变为客户端想要的另外一个接口,从而使原本因接口不匹配无法在一起工作的两个类能够在一起工作。适配器的目的是复用已有的功能。

适配器分为类适配器对象适配器两种

缺省适配:为一个接口提供缺省实现,一般是一个抽象类

适配器模式跟代理模式的不同之处:适配器模式中适配器和被适配对象中的接口方法不一致,适配器对被适配对象中的接口进行了改造或者扩展。代理模式中代理对象和被代理对象实现同一个接口,可以相互替换,代理对象只是对被代理对象中接口方法中的逻辑进行了改变,如添加权限控制。

思考

适配器模式可以对一个接口的所有子类进行适配,对象适配器中持有一个父类指针。不需要单独去对每个子类建立适配器。

适配器模式实质:转换接口,复用功能,通过适配器将老的接口实现类中的方法转换为新的接口中的方法

优先使用对象适配器,多用合成/聚合,少用继承。

使用场景

如果定义了新的接口跟已存在一个实现类不兼容,但是又在新的接口中又想使用实现类中方法,这时使用适配器模式实现复用实现类中的功能。

优缺点

  • 优点

    1. 更好的复用性:能够兼容使用老的接口
    2. 开闭原则:避免了对老接口的修改,通过添加适配器实现兼容,达到更好的扩展性
  • 缺点

    1. 过多的使用适配器模式,会导致调用零乱,明明调用A接口,在A接口中实际调用的是B接口,脱离控制。如果不是很有必要,可以不使用适配器,而是对系统进行重构。

UML图

类适配器:

采用继承方式,即适配器继承被适配类

image

  • 目标接口(Target):客户端真正想要的接口
  • 被适配接口(Adaptee):已有的接口实现类,与客户端最新需要的接口不兼容
  • 适配器(Adapter):适配器,实现Target和继承Adaptee,客户端调动Adapter,既可以调用Target中的接口方法,也可以调用Adapter继承Adaptee中老的方法

对象适配器:

使用对象动态组合方式,即适配器持有一个被适配对象

image

  • 目标接口(Target):客户端真正想要的接口
  • 被适配接口(Adaptee):已有的接口实现类,与客户端最新需要的接口不兼容
  • 适配器(Adapter):适配器,实现Target,持有一个Adaptee对象,对于新的接口,调用Adapter中实现的方法,对于老的方法,使用Adaptee对象进行调用

缺省适配

很多情况下,接口中定义了特别多方法,而一个类去实现一个接口,必须要实现所有的方法,但是有些类只是使用到了接口中很少的方法,对于不使用的方法就只能空着,这样会对客户端的调用造成困扰。这时就需要使用一个抽象类去实现接口,在抽象类中给出所有方法的”平庸”实现。从这个抽象类再继承下去的子类就不必实现所有的方法了。,在java源码中很多地方都使用到了这种处理,如List中等。缺省适配的用意是为了避免子类去处理自己不关注的接口方法

image

代码实现

类适配器:

适配器继承被适配对象,实现目标接口,客户端使用适配器进行调用,对于目标接口中新的方法,适配器进行实现,对于老的接口方法,调用适配器继承而来的被适配类中的方法,从而实现接口兼容。

/**
 * 客户端需要的接口
 */
public interface Target {
    /**
     * 这是源类Adaptee也有的方法
     */
    public void sampleOperation1(); 
    /**
     * 这是源类Adapteee没有的方法
     */
    public void sampleOperation2(); 
}
/**
 * 已经存在的接口实现,这个接口实现需要被适配
 */
public class Adaptee {
    public void sampleOperation1(){}
}
/**
 * 适配器,继承被适配类,实现目标接口
 */
public class Adapter extends Adaptee implements Target {
    /**
     * 由于源类Adaptee没有方法sampleOperation2()
     * 因此适配器补充上这个方法
     */
    @Override
    public void sampleOperation2() {
        //写相关的代码
    }
}

对象适配器:

适配器实现目标对象,通过构造方法持有一个被适配对象,客户端使用适配器进行调用,对于新的接口调用适配器中的方法,对于老的接口实现,适配器使用被适配对象调用被适配对象中的方法,从而实现接口兼容。

/**
 * 客户端需要的接口
 */
public interface Target {
    public void request1();
    public void request2();
}
/**
 * 已经存在的接口,这个接口需要被适配
 */
public class Adaptee {
    /**
     * 示意方法,原本已经存在,已经实现的方法
     */
    public void request1() {
        //具体的功能处理
    }
}
/**
 * 适配器
 */
public class Adapter implements Target {
    /**
     * 持有需要被适配的接口对象
     */
    private Adaptee adaptee;
    /**
     * 构造方法,传入需要被适配的对象
     * @param adaptee 需要被适配的对象
     */
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public void request1() {
        //可能转调已经实现了的方法,进行适配
        adaptee.request1();
    }
    public void request2() {
        //业务代码
    }
}
/**
 * 使用适配器的客户端
 */
public class Client {   
    public static void main(String[] args) {
        //创建需被适配的对象
        Adaptee adaptee = new Adaptee();
        //创建客户端需要调用的接口对象
        Target target = new Adapter(adaptee);
        //请求处理
        target.request();
    }
}

缺省适配:

使用抽象类实现接口,对接口中方法进行默认实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值