桥梁模式(Bridge)
桥梁模式属于结构类的设计模式,示意结构图如下:
桥梁模式所涉及的角色有:
● 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
● 修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
● 实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
● 具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现。
关键点:
1、抽象化角色可以通过向不同的实现化对象委派达到动态转换自己的目的
2、抽象化角色和实现化角色之间是聚合关系,而不是继承关系
如果 一个类需要知道另一个类的属性和方法,可以选择继承,也可以选择组合(聚合),在使用组合时,则需要持有对方的引用
以一个万能遥控的例子说明该模式的应用:(为了在同一个文件共存,代码中类前面的public都省略了)
1 package designpatterns.strucural; 2 3 //抽象角色--Abstraction 4 abstract class AbstractRemoteControl { 5 6 protected ITV tv; 7 8 public void bindImpl(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 } 24 //精确抽象角色--RefinedAbstraction 25 class PcRemoteControl extends AbstractRemoteControl { 26 27 @Override 28 public void turnOn() { 29 System.out.println("Pc On"); 30 } 31 } 32 33 class CommonRemoteControl extends AbstractRemoteControl{ 34 35 @Override 36 public void turnOn() { 37 super.turnOn(); 38 } 39 40 @Override 41 public void turnOff() { 42 super.turnOff(); 43 } 44 45 @Override 46 public void setChannel(int channel) { 47 super.setChannel(channel); 48 } 49 } 50 51 //实现角色--mplementor 52 /* 53 * 首先定义电视机的接口:ITV*/ 54 interface ITV { 55 56 public void on(); 57 public void off(); 58 public void switchChannel(int channel); 59 } 60 //具体实现角色--ConcreteImplementor1 61 /* 62 * 再实现三星的ITV接口。*/ 63 class SamsungTV implements ITV { 64 @Override 65 public void on() { 66 System.out.println("Samsung is turned on."); 67 } 68 69 @Override 70 public void off() { 71 System.out.println("Samsung is turned off."); 72 } 73 74 @Override 75 public void switchChannel(int channel) { 76 System.out.println("Samsung: channel - " + channel); 77 } 78 } 79 //具体实现角色--ConcreteImplementor2 80 /* 81 * 再实现索尼的ITV接口。*/ 82 class SonyTV implements ITV { 83 84 @Override 85 public void on() { 86 System.out.println("Sony is turned on."); 87 } 88 89 @Override 90 public void off() { 91 System.out.println("Sony is turned off."); 92 } 93 94 @Override 95 public void switchChannel(int channel) { 96 System.out.println("Sony: channel - " + channel); 97 } 98 } 99 100 //测试类 101 public class Bridge { 102 public static void main(String[] args){ 103 ITV tv1 = new SonyTV(); 104 ITV tv2 = new SamsungTV(); 105 106 AbstractRemoteControl control = new CommonRemoteControl(); 107 control.bindImpl(tv1); 108 control.turnOn(); 109 control.bindImpl(tv2); 110 control.turnOn(); 111 112 AbstractRemoteControl control_pc = new PcRemoteControl(); 113 control_pc.turnOn(); 114 } 115 }
验证输出:
Sony is turned on.
Samsung is turned on.
Pc On
代码说明:
抽象化角色:远程控制,通过持有ITV接口实例,达到对电视万能控制
修正抽象化角色:pc的远程控制,有朝一日,电视消失了,证明抽象化角色还可以复用
实现化角色:ITV ,这个可以定义为抽象类,也可以定义为接口,个人倾向定义为接口,毕竟代码量少
具体实现化角色:各品牌的电视
何时持有对方引用?
阎宏博士java与模式一书省略了这一点,不少博客的例子是通过构造函数传参的方式获取对方引用,也许是为了图省事儿
我觉得恰是这些省略让人不太好体会这个模式的特点,因为这么干就说不清楚和抽象工厂模式的区别了,像下面的代码
Animal A = new cat() A.run() Animal B = new dog() B.run()
持有对方引用通过调用一个普通方法
public void bindImpl(ITV tv){ this.tv = tv; }
这样就只需要有一个实例,通过绑定不同的实现化对象,达到动态转换自己功能
类似于现实中,你有一个万能遥控器,通过点击某个电视品牌,你就能实现对具体电视的控制
参考: