bboyjing's blog

HeadFirst设计模式十六【桥接模式】

从这个模式开始,都出现在书的附录中,属于不常用的模式。虽然这样,但是我们还是要学习下,哪怕简单地过一下,最起码要知道每个模式的作用是什么。桥接模式的定义是不只改变你的实现,也改变你的抽象。光从定义,不太能够直观地看出这个模式像干啥。下面还是从场景开始分析,慢慢带入进去。

场景描述

假设现在需要制造电视机的遥控器,每个遥控器都有相同的接口,但是每个电视机的实现各不相同。这个场景很简单,使用继承就能很好的解决问题,下面就按照最简单的方式来实现下。

  1. 遥控器抽象

    1
    2
    3
    4
    5
    6
    7
    public interface RemoteControl {
    void on();
    void off();
    void setChannel(int channel);
    }
  1. 实现RCA电视机对应的遥控器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class RCAControl implements RemoteControl {
    public int channel;
    @Override
    public void on() {
    System.out.println("RCA ON...");
    }
    @Override
    public void off() {
    System.out.println("RCA OFF...");
    }
    @Override
    public void setChannel(int channel) {
    this.channel = channel;
    System.out.println("RCA Tune to channel " + this.channel);
    }
    }
  2. 实现Sony电视机对应的遥控器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class SonyControl implements RemoteControl {
    public int channel;
    @Override
    public void on() {
    System.out.println("Sony ON...");
    }
    @Override
    public void off() {
    System.out.println("Sony OFF...");
    }
    @Override
    public void setChannel(int channel) {
    this.channel = channel;
    System.out.println("SONY Tune to channel " + this.channel);
    }
    }
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Test {
    public static void main(String[] args) {
    RemoteControl rca = new RCAControl();
    rca.on();
    rca.setChannel(9);
    rca.off();
    RemoteControl sony = new SonyControl();
    sony.on();
    sony.setChannel(12);
    sony.off();
    }
    }

场景跟实现代码都很简单,没什么好说的。但是后面通过用户反馈,需要来持续改进遥控器,这时候因为遥控器和电视机耦合在了一起,改变抽象的同时又要改变实现,就没有任何设计可言了。下面来看下桥接模式如何来应对这个场景。

代码示例

桥接模式通过将实现合抽象放在两个不同的类层次中而使它们可以独立改变。

  1. 遥控器抽象电视机抽象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface TV {
    void on();
    void off();
    void setChannel(int channel);
    int getChannel();
    }
  2. 遥控器抽象,这个和上面的电视机抽象就是上面说的两个不同的类层次

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public abstract class RemoteControl {
    protected TV tv;
    public RemoteControl(TV tv) {
    this.tv = tv;
    }
    abstract void on();
    abstract void off();
    abstract void setChannel(int channel);
    }
  3. 实现两个电视机

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class RCA implements TV {
    int channel;
    @Override
    public void on() {
    System.out.println("RCA ON...");
    }
    @Override
    public void off() {
    System.out.println("RCA OFF...");
    }
    @Override
    public void setChannel(int channel) {
    this.channel = channel;
    System.out.println("RCA Tune to channel " + this.channel);
    }
    @Override
    public int getChannel() {
    return this.channel;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class Sony implements TV {
    int channel;
    @Override
    public void on() {
    System.out.println("SONY ON...");
    }
    @Override
    public void off() {
    System.out.println("SONY OFF...");
    }
    @Override
    public void setChannel(int channel) {
    this.channel = channel;
    System.out.println("SONY Tune to channel " + this.channel);
    }
    @Override
    public int getChannel() {
    return this.channel;
    }
    }
  4. 实现遥控器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class ConcreteRemote extends RemoteControl {
    public ConcreteRemote(TV tv) {
    super(tv);
    }
    @Override
    public void on() {
    tv.on();
    }
    @Override
    public void off() {
    tv.off();
    }
    @Override
    public void setChannel(int channel) {
    tv.setChannel(channel);
    }
    public void nextChannel() {
    int currentChannel = tv.getChannel();
    tv.setChannel(++currentChannel);
    }
    public void previousChannel() {
    int currentChannel = tv.getChannel();
    tv.setChannel(--currentChannel);
    }
    }
  5. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class Test {
    public static void main(String[] args) {
    RCA rca = new RCA();
    ConcreteRemote rcaRemote = new ConcreteRemote(rca);
    rcaRemote.on();
    rcaRemote.setChannel(9);
    rcaRemote.off();
    Sony sony = new Sony();
    ConcreteRemote sonyRemote = new ConcreteRemote(sony);
    sonyRemote.on();
    sonyRemote.setChannel(12);
    sonyRemote.off();
    }
    }

假如现在需要在遥控器上增加上一个节目和下一个节目的功能,下面看下桥接模式如何轻松应对:

  1. 修改遥控器实现,添加两个方法实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class ConcreteRemote implements RemoteControl {
    ......
    public void nextChannel() {
    int currentChannel = tv.getChannel();
    tv.setChannel(++currentChannel);
    }
    public void previousChannel() {
    int currentChannel = tv.getChannel();
    tv.setChannel(--currentChannel);
    }
    }
  2. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Test {
    public static void main(String[] args) {
    RCA rca = new RCA();
    ConcreteRemote rcaRemote = new ConcreteRemote(rca);
    rcaRemote.on();
    rcaRemote.setChannel(9);
    rcaRemote.nextChannel();
    rcaRemote.nextChannel();
    rcaRemote.previousChannel();
    rcaRemote.off();
    Sony sony = new Sony();
    ConcreteRemote sonyRemote = new ConcreteRemote(sony);
    sonyRemote.on();
    sonyRemote.setChannel(12);
    sonyRemote.previousChannel();
    sonyRemote.previousChannel();
    sonyRemote.nextChannel();
    sonyRemote.off();
    }
    }

可见桥接模式确实实现了遥控器界面和电视机的解耦,而且遥控器和电视机可以独立扩展,不会影响到对方。本章节就到这里了。