设计模式:Bridge模式

Bridge模式,桥接,参考网络的桥接模式,这里的功能是将类的功能层次结构和类的实现层次结构连接起来

类的层次结构:

功能层次结构

实现层次结构

功能层次结构

如果有一个Something类,如果要在Something中增加新功能,比如一个具体方法,那么可以编写一个Something的子类,比如SomethingGood类,在子类中添加具体方法,这样Something和SomethingGood就构成了一个类层次结构;如果需要继续在SomethingGood类基础上又新增新的功能,可以编写一个SomethingGood的子类,比如SomethingBetter类,这样Something,SomethingGood,SomethingBetter就构成了一个类的层次结构,层次也加深了

实现层次结构

如果超类AbstractClass声明了一些抽象方法,子类ConncreteClass实现了超类的抽象方法,这样它们之间就构成了一个小小的层次结构,但这个层次结构并没有增加功能,它的功能也并非方便新增新的方法,而是为了实现任务分担:超类通过声明抽象方法来定义接口,子类通过实现具体方法来实现接口,这就是类的实现层次结构;假如又多了一种方式来实现AbstractClass,比如通过AnotherConcreteClass实现,层次结构ConcreteClass和AnotherConcreteClass是并列的关系,都继承超类,并各自实现了抽象方法

根据上面两种层次结构,当需要新增子类时,得需要知道是增加功能还是增加实现,这两者是分离的,既然是分离就缺少联系,因此如果这两者需要建立连接,就需要一个桥梁,这就是Bridge模式的作用

下面的例子,根据输入的字符串,按要求显示出来

具体的类如下

Display:类的功能层次结构,负责显示的类

CountDisplay:类的功能层次结构,增加了只显示规定次数功能的类

DisplayImpl:类的实现层次结构,负责显示的类

StringDisplayImpl:类的实现层次结构,用字符串显示的类

Main:main,测试

Display类,作为功能层次的最上层

impl字段作为两个层次结构的桥梁,保存了具体实现的实例,通过构造函数的参数传递给Display类,而Display类提供open,print,close三个方法都调用了impl字段的实现方法,这样Display的接口就被转换成了DisplayImpl的接口

package bridge;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: Display
* Author: lihui
* Date: 2018/5/5 23:01
*/

public class Display {
private DisplayImpl impl;
public Display(DisplayImpl impl) {
this.impl = impl;
}

public void open() {
impl.rawOpen();
}

public void print() {
impl.rawPrint();
}

public void close() {
impl.rawClose();
}

public final void display() {
open();
print();
close();
}
}

CountDisplay类,在Display类基础上新增一个功能,具有只显示规定的次数的multiDisplay方法

CountDisplay类继承了Display类的open,print,close方法,使用它们来新增功能,这就是类的功能层次结构

package bridge;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: CountDisplay
* Author: lihui
* Date: 2018/5/5 23:01
*/

public class CountDisplay extends Display {
public CountDisplay(DisplayImpl impl) {
super(impl);
}

public void multiDisplay(int times) {
open();
for (int i = 0; i < times; i++) {
print();
}
close();
}
}

DisplayImpl类,类的实现层次结构

DisplayImpl是抽象类,声明了3个抽象方法,分别于Display类的open,print,close方法对应 ,进行显示前,显示,显示后处理

package bridge;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: DisplayImpl
* Author: lihui
* Date: 2018/5/5 23:02
*/

public abstract class DisplayImpl {
public abstract void rawOpen();
public abstract void rawPrint();
public abstract void rawClose();
}

StringDisplayImpl类,真正的实现,显示字符串的类,继承DisplayImpl类,作为子类来使用rawOpen,rawPrint,rawClose方法显示

package bridge;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: StringDisplayImpl
* Author: lihui
* Date: 2018/5/5 23:02
*/

public class StringDisplayImpl extends DisplayImpl {
private String string;
private int width;
public StringDisplayImpl(String string) {
this.string = string;
this.width = string.getBytes().length;
}

@Override
public void rawOpen() {
printLine();
}

@Override
public void rawPrint() {
System.out.println("|" + string + "|");
}

@Override
public void rawClose() {
printLine();
}

private void printLine() {
System.out.print("+");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("+");
}
}

Main类,将上述类组合起来显示字符串;虽然d1保存Display实例,d2和d3保存CountDisplay实例,但内部都是保存了StringDisplayImpl实例

package bridge;

/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: Main
* Author: lihui
* Date: 2018/5/5 23:02
*/

public class Main {
public static void main(String[] args) {
Display d1 = new Display(new StringDisplayImpl("Hello, My Love"));
Display d2 = new CountDisplay(new StringDisplayImpl("Hello, World"));
CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, LiHui"));
d1.display();
d2.display();
d3.display();
d3.multiDisplay(5);
}
}

 

Bridge模式的角色:

Abstraction:抽象化,例子中的Display类;使用Implementor角色的方法定义了基本功能,保存了Implementor角色的实例

RefinedAbstraction:改善后的抽象化,例子中的CountDisplay类;在Abstraction角色基础上增加新功能的角色

Implementor:实现者,例子中的DisplayImpl类;定义了用于实现Abstraction角色的接口方法

ConcreteImplementor:具体实现者,例子中的StringDisplayImpl类,负责实现在Implementor角色中定义的接口

类的两个层次结构之间的桥梁就是impl字段

 

继承是强关联,委托是弱关联

虽然使用继承很容易扩展类,但是类之间也形成了一种强关联关系,如果想改变类之间的关系,就必须要修改程序;而上面例子中Display类使用了委托,impl字段保存了实现的实例,这样,类的任务就发生了转移

调用open方法会调用impl.rawOpen()方法

调用print方法会调用impl.rawPrint()方法

调用close方法会调用impl.rawClose()方法

也就是说,当其它类需要Display类工作的时候,Display类并非自己干,而是将工作交给了impl

继承是强关联关系,委托是弱关联关系,因为只有Display类的实例生成的时候,才与作为参数被传入的类构成关联;例子中Main类生成Display类和CountDisplay类的实例时,才将StringDisplayImpl的实例作为参数传递给Display类和CountDisplay类;对于其它实现,只需要将其它ConcreteImplementor角色的实例传递给Display类和CountDisplay类,就能很容易改变实现,这时候需要变化的代码只有Main类,Display类和DisplayImpl类不需要做任何修改

发表评论