设计模式(七)———桥接模式(Bridge Method):将类的功能层次结构与实现层次结构分离

设计模式(七)———桥接模式(Bridge Method):将类的功能层次结构与实现层次结构分离

Scroll Down

Intent

将抽象部分与它的实现部分分离,使他们都可以独立地变化。

应用实例

  • 猪八戒从天蓬元帅转世投胎到猪,转世投胎的机制将尘世划分为两个等级,即:灵魂和肉体,前者相当于抽象化,后者相当于实现化。生灵通过功能的委派,调用肉体对象的功能,使得生灵可以动态地选择。
  • 墙上的开关,可以看到的开关是抽象的,不用管里面具体怎么实现的。

使用场景

  • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  • 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
  • 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

优点

  • 抽象和实现的分离。
  • 优秀的扩展能力。
  • 实现细节对客户透明。

缺点

  • 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

Class Diagram

image.png

Abstraction(抽象化)

该角色位于“类的功能层次结构”最上层。它使用Implementor角色的方法定义了基本的功能。

RefinedAbstraction(改善后的抽象化)

Abstraction角色的基础上增加了新功能的角色。

Implementor(实现者)

该角色位于“类的实现层次结构”的最上层。它定义了用于实现Abstraction角色的接口(API)的方法。

ConcreteImplementor(具体实现者)

该角色负责在Implementor角色中定义的接口(API)。

功能层次结构与实现层次结构

类的功能层次结构是为了增加新功能而产生的层次结构。

  • 父类中具有基本功能;

  • 在子类中增加新的功能;

类的实现层次结构的不是方便我们增加新的方法,而是为了实现下面这样的任务分担:

  • 父类通过声明抽象方法来定义接口(API);

  • 子类通过实现具体方法来实现接口(API);

在编写子类时,需要先确认自己的意图:“我是要增加功能呢?还是要增加实现呢?”当类的层次结构只有一层时,功能层次结构与实现层次结构是混杂在一个层次结构中的。这样很容易使类的层次结构变得复杂,也难以透彻地理解类的层次结构。因为自己难以确定究竟应该在类的哪一个层次结构去增加子类。

因此需要将“类的功能层次结构”与“类的实现层次结构”分离为两个独立的类层次结构。还需要在它们之间搭建一座桥梁。

Implementation

RemoteControl 表示遥控器,指代 Abstraction

TV 表示电视,指代 Implementor

桥接模式将遥控器和电视分离开来,从而可以独立改变遥控器或者电视的实现。

Implementor

public abstract class TV {
    public abstract void on();

    public abstract void off();

    public abstract void tuneChannel();
}

ConcreteImplementor

public class Sony extends TV {
    @Override
    public void on() {
        System.out.println("Sony.on()");
    }

    @Override
    public void off() {
        System.out.println("Sony.off()");
    }

    @Override
    public void tuneChannel() {
        System.out.println("Sony.tuneChannel()");
    }
}
public class RCA extends TV {
    @Override
    public void on() {
        System.out.println("RCA.on()");
    }

    @Override
    public void off() {
        System.out.println("RCA.off()");
    }

    @Override
    public void tuneChannel() {
        System.out.println("RCA.tuneChannel()");
    }
}

Abstraction

public abstract class RemoteControl {
    protected TV tv;

    public RemoteControl(TV tv) {
        this.tv = tv;
    }

    public abstract void on();

    public abstract void off();

    public abstract void tuneChannel();
}

RefinedAbstraction

public class ConcreteRemoteControl1 extends RemoteControl {
    public ConcreteRemoteControl1(TV tv) {
        super(tv);
    }

    @Override
    public void on() {
        System.out.println("ConcreteRemoteControl1.on()");
        tv.on();
    }

    @Override
    public void off() {
        System.out.println("ConcreteRemoteControl1.off()");
        tv.off();
    }

    @Override
    public void tuneChannel() {
        System.out.println("ConcreteRemoteControl1.tuneChannel()");
        tv.tuneChannel();
    }
}
public class ConcreteRemoteControl2 extends RemoteControl {
    public ConcreteRemoteControl2(TV tv) {
        super(tv);
    }

    @Override
    public void on() {
        System.out.println("ConcreteRemoteControl2.on()");
        tv.on();
    }

    @Override
    public void off() {
        System.out.println("ConcreteRemoteControl2.off()");
        tv.off();
    }

    @Override
    public void tuneChannel() {
        System.out.println("ConcreteRemoteControl2.tuneChannel()");
        tv.tuneChannel();
    }
}

clinet

public class Client {
    public static void main(String[] args) {
        RemoteControl remoteControl1 = new ConcreteRemoteControl1(new RCA());
        remoteControl1.on();
        remoteControl1.off();
        remoteControl1.tuneChannel();
        RemoteControl remoteControl2 = new ConcreteRemoteControl2(new Sony());
         remoteControl2.on();
         remoteControl2.off();
         remoteControl2.tuneChannel();
    }
}

结果:

ConcreteRemoteControl1.on()
RCA.on()
ConcreteRemoteControl1.off()
RCA.off()
ConcreteRemoteControl1.tuneChannel()
RCA.tuneChannel()

ConcreteRemoteControl2.on()
Sony.on()
ConcreteRemoteControl2.off()
Sony.off()
ConcreteRemoteControl2.tuneChannel()
Sony.tuneChannel()