十四 结构型-适配器模式(bridge)

183 阅读3分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

image.png 其他设计模式介绍
创建型: 工厂方法 抽象工厂 原型
结构型: 适配器 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式
行为型: 职责链 命令 解释器 迭代器 中介者 备忘录 状态模式 策略模式 模板方法 访问者

定义

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。从而大大提高程序的兼容性。

工作原理

用户调用适配器转换出来的接口,适配器在调用被适配类的相关接口,从而完成适配。

通过不同的实现方式,我们可以将其分成三类:类适配器模式,对象适配器模式,接口适配器模式

缺点

java是单继承语言,类适配器模式又需要继承被适配的类,这就导致必须存在一个适配器接口。从这点就可以看出该模式是有一定局限性。并且因继承了被适配的类,所以类的所有方法都暴露在了适配器类中,从而增加了使用成本。

优点

由于继承了“被适配的类”,所以可以根据需求重写父类的方法,从而增加了代码的灵活性。

UML图

image.png

举个例子

public interface TargetPlayer {
    public void playMp4();
    public void playAVI();
}

public interface AdapteePlayer {
    public void playMp4();
}

public class AdapteePlayerImpl implements AdapteePlayer {
    public void playMp4() {
        System.out.println("can play mp4");
    }
}

public class Adapter implements TargetPlayer{
    private AdapteePlayer adapteePlayer;

    public void setAdapteePlayer(AdapteePlayer adapteePlayer) {
        this.adapteePlayer = adapteePlayer;
    }

    public void playMp4() {
        adapteePlayer.playMp4();
    }

    public void playAVI() {
        System.out.println("can play avi");
    }
}

public class AdapterMain {
    public static void main(String[] args) {
        Adapter adapter=new Adapter();
        AdapteePlayer adapteePlayer=new AdapteePlayerImpl();
        adapter.setAdapteePlayer(adapteePlayer);
        adapter.playAVI();
        adapter.playMp4();
    }
}

使用场景

  1. 灵活使用时:选择对象的适配器模式
    类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
  2. 需要同时配源类和其子类:选择对象的适配器
  • 对于类适配器,由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理 Adaptee的子类了;
  • 对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓。
  1. 需要重新定义Adaptee的部分行为:选择类适配器
  • 对于类适配器,适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。
  • 对于对象适配器,要重定义Adaptee的行为比较困难,这种情况下,需要定义Adaptee的子类来实现重定义,然后让适配器组合子类。虽然重定义Adaptee的行为比较困难,但是想要增加一些新的行为则方便的很,而且新增加的行为可同时适用于所有的源。
  1. 仅仅希望使用方便时:选择类适配器
  • 对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee。
  • 对于对象适配器,需要额外的引用来间接得到Adaptee。

总结

建议尽量使用对象的适配器模式,多用合成/聚合、少用继承。