1、现象分析
在软件产品的研发过程中,随着开发过程的逐步深入,我们避免不了地需要“改”程序。程序开发人员可以使用面向对象继承的特征,实现程序的重用和改写,从而使程序适应开发过程中的变化,有效地解决程序的扩展问题。
使用面向对象技术研发软件产品,存在着这样一种情况,一类事物的变化与其它多类事物存在着牵连,也就是说,通常一类事物引起变化的因素比较多。这时,就使得当其它部分出现变化时,需要更改前一类事物。虽然使用面向对象继承的机制可以实现程序要求,但会使程序中类的数量成爆炸性增长。例如:以生产可乐为例,可乐可以根据瓶子的尺寸分为大瓶可乐和小瓶可乐,还可以根据生产厂商的不同分为百事可乐和可口可乐。
仔细分析上面的类图,会发现这样一个问题:使用继承机制扩展可乐的生产实现,会给开发带来很多不便。如果增加一个可乐的生产厂商,这个厂商需要分别做大瓶可乐和小瓶可乐两种实现;如果程序要添加一种新的可乐尺寸,程序需要为所有已有厂商添加新尺寸的实现。在这种情况下,我们发现扩展程序虽能实现,但实现不方便,结构繁杂。那么,有没有什么办法能够更好的解决灵活扩展的问题呢?有,那就是桥梁模式。
2、桥梁模式实现
桥梁模式的核心思想将抽象部分与它的实现部分分离,使它们都可以独立地变化。在生产可乐饮料的例子中,我们使用继承的实现方式实质上创建了一种强性关联,使用桥接方式可以将强性关联转变成弱关联,也就是脱耦。
桥梁模式中的角色:
抽象角色:定义抽象类的接口而且维护着一个指向实现角色的引用。
精确抽象角色:实现并扩充由抽象角色定义的接口。
实现角色:定义实现类的接口,接口与抽象角色中的接口可以不一致。
具体实现角色:定义实现角色定义接口的具体实现。
3 实现代码
(1)实现接口的定义
主要任务是定义抽象部分需要的功能,仅完成抽象功能定义。但需要注意,其定义形式可以与抽象部分的定义形式不同,示意代码如下:
public interface 实现
{
void 实现操作();
}
(2)抽象部分的定义
在此部分需要调用实现部分定义的操作。因此,在抽象部分需要持有实现部分的引用,构建具体抽象对象时指定具体实现的对象,使程序基于组合的结构方式完成功能。示意代码如下:
public abstract class 抽象
{
protected 实现实现引用;
public 抽象(实现实现引用)
{
this.实现引用 =实现引用 ;
}
public void 操作()
{
实现引用.实现操作();
}
}
(3)具体实现的定义
完成实现接口定义的抽象方法,示意代码如下:
具体实现1:
public class 具体实现1 implements 实现
{
public void 实现操作()
{
//具体实现操作
}
}
具体实现2:
public class 具体实现1 implements 实现
{
public void 实现操作()
{
//具体实现操作
}
}
(4)精确抽象的定义
其泛化了抽象部分,具备抽象部分开放的操作,完成了更为具体的操作,示例代码如下:
精确抽象1:
public class 精确抽象1 extends 抽象
{
public 精确抽象1(实现 实现引用)
{
super(实现引用);
}
public void 其他操作()
{
//通过使用抽象中定义的方法来扩展的功能
}
}
精确抽象2:
public class 精确抽象2 extends 抽象
{
public 精确抽象1(实现 实现引用)
{
super(实现引用);
}
public void 其他操作()
{
//通过使用抽象中定义的方法来扩展的功能
}
}
(5)客户端调用
在客户端调用时,首先根据需求创建一个实现部分的具体实现对象。然后,通过实现部分的具体实现对象创建抽象部分一个具体的抽象对象。最后,通过抽象引用调用某项功能。
结论
为了使程序能够灵活地扩展,在桥接模式中将程序的抽象部分与实现部分分离,使得这两个部分可以独立变化。虽然在结构上分离,但在抽象部分需要使用实现部分中的操作。所以,在抽象部分需要持有实现部分的引用,这个持有的引用就是桥接的体现。有了这个引用,就使得软件的结构分离,但抽象部分又可以方便地调用实现的操作,从而使程序的不同部分通过组合的方式构成松散耦合的关系,进而减少关联,适应改变。
参考文献:
[1] 陈臣,王斌. 研磨设计模式[M].北京:清华大学出版社. 20011.1
[2] 阎宏. Java与模式[M]. 北京:电子工业出版社. 2002.10
[3] 唐大仕. Java程序设计[M]. 北京:北方交通大学出版社. 2003. 3
[4] 殷兆麟. Java语言程序设计[M]. 北京:高等教育出版社. 2003.7