1. Java之桥接模式(Bridge Pattern)
(1)概述:
首先我们说一个生活中的例子:
就拿汽车在路上行驶的来说。即有小汽车又有公共汽车,它们都不但能在市区中的公路上行驶,也能在高速公路上行驶。这你会发现,对于交通工具(汽车)有不同的类型,然而它们所行驶的环境(路)也在变化,在软件系统中就要适应两个方面的变化?怎样实现才能应对这种变化呢 ?
如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ? 这就要使用Bridge模式。
(2)桥接模式的意图:
桥接模式是用于“把抽象和实现分开,这样它们就能独立变化”。 桥接模式使用了封装、聚合,可以用继承将不同的功能拆分为不同的类。
2. 桥接模式UML图:
3. 桥接模式代码实现:
(1)Implementor : 定义实现接口
1 interface Implementor { 2 // 实现抽象部分需要的某些具体功能 3 public void operationImpl(); 4 }
(2)Abstraction : 定义抽象接口
1 abstract class Abstraction { 2 3 // 持有一个 Implementor 对象,形成聚合关系 4 protected Implementor implementor; 5 6 public Abstraction(Implementor implementor) { 7 this.implementor = implementor; 8 } 9 10 // 可能需要转调实现部分的具体实现 11 public void operation() { 12 implementor.operationImpl(); 13 } 14 15 }
(3)ConcreteImplementor : 实现 Implementor 中定义的接口
1 class ConcreteImplementorA implements Implementor { 2 @Override 3 public void operationImpl() { 4 // 真正的实现 5 System.out.println("具体实现A"); 6 } 7 } 8 9 10 class ConcreteImplementorB implements Implementor { 11 @Override 12 public void operationImpl() { 13 // 真正的实现 14 System.out.println("具体实现B"); 15 } 16 }
(4)RefinedAbstraction : 扩展 Abstraction 类
1 class RefinedAbstraction extends Abstraction { 2 3 public RefinedAbstraction(Implementor implementor) { 4 super(implementor); 5 } 6 public void otherOperation() { 7 // 实现一定的功能,可能会使用具体实现部分的实现方法, 8 // 但是本方法更大的可能是使用 Abstraction 中定义的方法, 9 // 通过组合使用 Abstraction 中定义的方法来完成更多的功能。 10 } 11 }
(5)测试代码:
1 public class BridgePattern { 2 public static void main(String[] args) { 3 Implementor implementor = new ConcreteImplementorA(); 4 RefinedAbstraction abstraction = new RefinedAbstraction(implementor); 5 abstraction.operation(); 6 abstraction.otherOperation(); 7 } 8 }
运行结果:
1 具体实现A 2 其他操作
4. 桥接模式应用场景:
(2)如果出现抽象部分和实现部分都应该可以扩展的情况,可以采用桥接模式,让抽象部分和实现部分可以独立的变化,从而可以灵活的进行单独扩展,而不是搅在一起,扩展一边会影响到另一边。
(3)如果希望实现部分的修改,不会对客户产生影响,可以采用桥接模式,客户是面向抽象的接口在运行,实现部分的修改,可以独立于抽象部分,也就不会对客户产生影响了,也可以说对客户是透明的。
(4)如果采用继承的实现方案,会导致产生很多子类,对于这种情况,可以考虑采用桥接模式,分析功能变化的原因,看看是否能分离成不同的纬度,然后通过桥接模式来分离它们,从而减少子类的数目。
5. 桥接模式的应用案例:
(1)桥接模式的故事:
电视和遥控器(图中有错字)是一个完美展示两层抽象的例子。你有一个电视机的接口,还有一个遥控器的抽象类。我们都知道,将它们中任何一个定义为一个具体类都不是好办法,因为其它厂家会有不同的实现方法。
(2)桥接模式Java示例代码:
首先定义电视机的接口:ITV
1 public interface ITV { 2 public void on(); 3 public void off(); 4 public void switchChannel(int channel); 5 }
实现ITV 接口的三星电视机:
1 public class SamsungTV implements ITV { 2 @Override 3 public void on() { 4 System.out.println("Samsung is turned on."); 5 } 6 7 @Override 8 public void off() { 9 System.out.println("Samsung is turned off."); 10 } 11 12 @Override 13 public void switchChannel(int channel) { 14 System.out.println("Samsung: channel - " + channel); 15 } 16 }
实现ITV 接口的索尼电视机:
1 public class SonyTV implements ITV { 2 3 @Override 4 public void on() { 5 System.out.println("Sony is turned on."); 6 } 7 8 @Override 9 public void off() { 10 System.out.println("Sony is turned off."); 11 } 12 13 @Override 14 public void switchChannel(int channel) { 15 System.out.println("Sony: channel - " + channel); 16 } 17 }
下面是遥控器的抽象类,而且这个遥控器要包含对TV的引用,这样就起到了"桥梁"的作用:连接"抽象部分" 和 "实现部分".
1 public abstract class AbstractRemoteControl { 2 /** 3 * @uml.property name="tv" 4 * @uml.associationEnd 5 */ 6 private ITV tv; 7 8 public AbstractRemoteControl(ITV tv){ 9 this.tv = tv; 10 } 11 12 public void turnOn(){ 13 tv.on(); 14 } 15 16 public void turnOff(){ 17 tv.off(); 18 } 19 20 public void setChannel(int channel){ 21 tv.switchChannel(channel); 22 } 23 }
定义遥控器的具体类:
1 public class LogitechRemoteControl extends AbstractRemoteControl { 2 3 public LogitechRemoteControl(ITV tv) { 4 super(tv); 5 } 6 7 public void setChannelKeyboard(int channel){ 8 setChannel(channel); 9 System.out.println("Logitech use keyword to set channel."); 10 } 11 }
测试类:
1 public class Main { 2 public static void main(String[] args){ 3 ITV tv = new SonyTV(); 4 LogitechRemoteControl lrc = new LogitechRemoteControl(tv); 5 lrc.setChannelKeyboard(100); 6 } 7 }
输出结果,如下:
Sony: channel – 100
Logitech use keyword to set channel.
总结一下, 桥接模式允许两层实现的抽象,上面的电视机和遥控器就是很好的例子。可见,桥接模式提供了更多的灵活性。