概念:
Bridge:将抽象部分与它的实现部分分离,使它们都可以独立地变化。 --------------------------------------
烈日,当空;没有一丝风,真的让人感觉透不过气来。想起去年夏天在没有空调的房子里写代码,^_^,真是对人性的一种考验。AndyTao正想着,不觉笑了。午休时间也快过了,继续写我的代码吧。 “Andy,过来帮我看看嘛!”一串银铃声传了过来。 “唉,美女相邀,怎能不动啊。”AndyTao心里想着,没敢说出口。“我说,你又怎么了?就你事多。” “上次技术讨论会上听你说过,如果一个抽象类或者接口有多个具体的实现类(concrete subclass)的时候,为了不至于由于使用单纯继承进行抽象类或接口的具体实现而导致代码混乱和可重用性不强,你说应当采用Bridge设计模式,这是怎么一回事啊?你看我现在这个例子采用继承不是很好吗?” “哦,我看看。”
public interface Draw
{
public void paint();
}
public class DrawCircle implements Draw
{
public void paint()
{
System.out.println("paint Circle");
……
}
……
}
public class DrawAngle implements Draw
{
public void paint()
{
System.out.println("paint Angle");
……
}
……
}
“你看看,我这里不是各干其事,做得挺好嘛。”
“呵呵,听我细细讲来。
通常, 当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以下两种情况:第一种是,这多个具体实现之间恰好是并列关系,就像你的这段代码,有两个 concrete class:画圆和画三角;这两个形状上的图形是并列的,没有相对概念上的重复,那么我们只要使用继承就可以了。……”
"别卖关子了好不好!”“……”
“好啦好啦,我请你喝可乐可以吧?”
嘿嘿,奸计得逞,AndyTao继续说道,“
但是,我们要考虑到第二种情况,如果我们两个或多个具体实现之间有概念重复,那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口,分别放置抽象部分和行为部分。” “好抽象啊,我听不懂!” “那好,我们来举个例子,嗯……,就拿可乐来说吧,我们喝的可乐有大杯和小杯之分,而又有加冰和不加冰之分,这样,如果我们采用单纯继承来实现这四个具体实现(大杯加冰,大杯不加冰,小杯加冰,小杯不加冰),那么很容易造成相互之间的概念重叠,而且代码混乱,不容易维护。所以……” “所以,怎么?继续继续。” “所以啊,我们就要采用Bridge模式来重新设计类的结构。如果采用Bridge模式,我们就需要定义两个接口或抽象类,为的是把抽象部分和行为部分分隔开来。” “稍等稍等,喝口水先。”“来来来,用我的吧。”“那……,真不好意思了,嘿嘿……” “我们就用可乐作例子吧。将可乐定义为抽象类,有一部分共同的实现代码可以放到里面,加冰和不加冰属于行为,那么我们就把它定义成为行为接口。” “然后,我们可以实现下面的抽象类。”
public abstract class Coke
{
CokeImp cokeImp;
public void setCokeImp(CokeImp cokeImp)
{
this.cokeImp = cokeImp;
}
public CokeImp getCokeImp()
{
return this.cokeImp;
}
public abstract void distributeCoke();
}
public abstract class CokeImp
{
public abstract void distributeCokeImp();
}
“现在,我们就有了两个抽象类(或接口)。上面,Coke是抽象部分,CokeImp是定义的行为抽象类。为了实现我们所说的四种类动态结合的功能,我们需要在具体实现类上下点功夫罗。”
“这是大可乐:”
public class BigCoke extends Coke
{
public BigCoke() {}
public void distributeCoke()
{
System.out.print("BigCoke ");
CokeImp cokeImp = this.getCokeImp();
cokeImp.distributeCokeImp();
}
}
“这是小可乐:”
public class SmallCoke extends Coke
{
public SmallCoke() {}
public void distributeCoke()
{
System.out.print("SmallCoke ");
CokeImp cokeImp = this.getCokeImp();
cokeImp.distributeCokeImp();
}
}
“我要加冰:”
public class IceCokeImp extends CokeImp
{
IceCokeImp() {}
public void distributeCokeImp()
{
System.out.print("Ice added");
}
}
“不要冰了:”
public class NonIceCokeImp extends CokeImp
{
NonIceCokeImp() {}
public void distributeCokeImp()
{
System.out.print("Havn't ice");
}
}
“这里需要注意了,由于我们的CokeImp和Coke是一对一的关系,所以要从我们的用例中找到这个*Imp是一个比较关键和困难的事情。”
“好啦,现在,你想喝哪种可乐?” “我要小杯可乐加冰!”“这个简单,给你……”
Coke coke = new SmallCoke();
coke.setCokeImp(new IceCokeImp());
coke.distributeCoke(); “我要大杯可乐不加冰!”
“Oh,Here!”
Coke coke = new BigCoke();
coke.setCokeImp(new NonIceCokeImp());
coke.distributeCoke(); “差不多Bridge模式就讲完了,另外,Bridge被广泛的应用于GUI和其它图形图象应用程序种,包括Java AWT。另外,Abstract Factory(抽象工厂模式)经常用来创建和设定一个Bridge,Bridge模式类似于Adapter(适配器模式)中的对象适配器模式。上面的两个模式上次不是都对你讲过了嘛。” “哦,你一说我到想起来了,”Helen咬着手指,非常可爱的模样。“哇,迷死人了!”AndyTao只有偷偷想的份。^_^ “不过,你还要注意了,你在设计Bridge类的时候,要注意对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。另外,Bridge 将会有许多类要生成,这样一种类层次结构说明你必须将一个对象分解成两个部分,抽象部分和实现部分。总之一句话,将抽象部分与它的实现部分分离,使它们都可以独立地变化。这就是Bridge模式的精髓所在了,还有……” “还有什么,跟个唐僧似的。”“还有啊,别忘了你的可乐!哈哈哈!!” “你呀,什么都记不住,就这在行。” “哇,你这么了解我啊。”“去死吧你……”“哈哈哈!!!”
作者:yakuu 来源: yakuu 的 Blog http://www.csai.cn