Bridge(桥)模式

来源:互联网 发布:2016-2017杜兰特数据 编辑:程序博客网 时间:2024/04/30 01:13

Bridge(桥)模式

 

GoF:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

解释一下GoF的定义:就是指将抽象部分和实现部分分开,让它们各自随意增加减少。而不受其它约束。

 

下面引自《Thinking in Patterns with Java》:

Bridge模式实际上就是一个组织代码的工具,它使得你可以添加任意数量的新的前端服务,而这些前端服务又可以通过把这些操作委托给任意数量的后端对象来实现。通过使用Bridge模式,你可以避免(类)组合所带来的类的数目的爆炸性增长。但是别忘了Bridge模式所处理的一系列变化通常都是发生在编码阶段:当为了实现某个功能而必须处理越来越多的选项(options)时,Bridge模式可以使你的代码保持条例性。

 

通常,当一个抽象类(或接口)有多个实现(派生类),这些实现(派生类)之间可能有以下两种情况:

1.       这些实现之间是并列的关系。如:我们要实现各类动物的睡觉方式,蝙蝠是倒挂着睡觉而狗是爬着睡觉。这两种动物的睡觉方式是并列的,没有概念上的重复。这时候我们使用继承就可以解决问题了。即使有更多种的动物,继承也可以自如的应付。

2.       实际应用上,常常有可能在这多个实现类之间有概念上重叠.那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口,分别放置抽象和行为。

 

Bridge模式适用于“一个抽象部分拥有不同的实现部分”的情况。“让抽象部分和实现部分可以独立地变化”意味着我可以在不改变实现部分的前提下为抽象部分增加新的内容,反之亦然。

 

下面举一个通俗的例子来说明Bridge模式的运用:

假如我们的系统中需要实现一个画图的功能(这样的需求是真实存在的,我的前一家公司做了个票务输出软件,其中就有画图的功能,那个软件使用C#实现的,图画的非常漂亮)。现在需要画一个圆,圆有两种要求:一种“彩色图”,一种“无彩图”。我们的传统做法是写出一个抽象类Circle然后派生出类两个类,这样的做法是非常正确的,也符合OO思想。但他只符合我们上面所说的第一种情况。其他情况可能就不适应了,比如说“彩色图”分大小,那么就会产生四个图形(也就是四个类):大彩色图,大无彩图,小彩色图,小无彩图。这时候你可能会说再从抽象类Circle继承不就完了么?但是,如果现在有画矩形的要求怎么办呢?再定义一个Rectangle类,来四个继承?或者是干脆定义一个ShapeCircleRectangle两个类来继承然后再分别派生类?如果我要增加其他图形呢?我们的类成核裂变式的增长,麻烦吗?再说我们的整个系统容许我们在增加新的类层次么?回答肯定是否定的。怎么办呢?Bridge模式可以帮我们轻松搞定。

 

我们上面说了:Bridge模式是将抽象部分与它的实现部分分离,使它们都可以独立地变化。

先实现抽象部分:

package Bridge;

 

public abstract class DrawGraph

{

       private Colourful colour; //彩色

      

       public void setColour() //设置所需要的彩色

       {

              this.colour = GpColorSingleton.getTheColor();

       }

      

       public Colourful getColour() //得到所需要的彩色

       {

              return colour;

       }

      

       public abstract void drawGp(); //抽象方法,待派生类自己实现

}//end abstract class DrawGraph

 

package Bridge;

 

public abstract class Colourful

{

       public abstract void drawColourfulGp();

       //do something....

}//end class Colourful

 

这里的抽象部分是可以随便加的,如果你需要3D效果也可以加一个抽象的3D类。在后面的实现部分,将此3D类实现出来就可以。

 

下面实现派生类部分:

package Bridge;

 

public class DrawBigCircle extends DrawGraph

{

       public DrawBigCircle()

       {

              this.setColour();//继承而来

       }// end DrawCircle

      

       public void drawGp()

       {

              Colourful color = this.getColour();//继承而来

              color.drawColourfulGp();//决定是否彩色

       }//end drawGp

}//end class DrawCircle

 

package Bridge;

 

public class DrawSmallCircle extends DrawGraph

{

 

       public DrawSmallCircle()

       {

              this.setColour();//继承而来

       }// end DrawCircle

      

       public void drawGp()

       {

              Colourful color = this.getColour();//继承而来

              color.drawColourfulGp(); //决定是否彩色

       }//end drawGp

 

}

上面两个类实现了图形的画法。下面是是否加颜色的设置。

package Bridge;

 

public class ColorGp extends Colourful {

 

       public ColorGp()

       {

              //do something....

       }//end ColorGp()

 

       public void drawColourfulGp()

       {

              System.out.println("彩色图形");

       }//end drawColourfulGp()

      

}//end class ColorGp

 

package Bridge;

 

public class UnColorGp extends Colourful {

 

       public UnColorGp()

       {

              // do something....

       }//end UnColorGp()

 

       public void drawColourfulGp()

       {

              System.out.println("无彩--图形");

       }//end drawColourfulGp()

 

}//end class UnColorGp

 

实现部分完成了,如果你在抽象部分家了3D的要求,那么在实现部分也要相应得实现出来。下面用一个单态类来hold我们的Colourful类:

package Bridge;

 

public class GpColorSingleton

{

       private static Colourful colorful;

      

       public GpColorSingleton(Colourful colorful)

       {

              this.colorful = colorful;

       }//end GpColorSingleton(...)

      

       public static Colourful getTheColor()

       {

              return colorful;

       }//end getTheColor()

 

}//end class GpColorSingleton

最后我们给出一个实现看看,彩色图和无彩图是怎么画出来的:

package Bridge;

 

public class BridgePattern

{

       GpColorSingleton gpColorSingleton = new GpColorSingleton(new ColorGp());

       DrawBigCircle bigCircle = new DrawBigCircle();

 

       GpColorSingleton gpUnColorSingleton = new GpColorSingleton(new UnColorGp());

       DrawSmallCircle smallCircle = new DrawSmallCircle();

      

       public void play()

       {

              bigCircle.drawGp(); //画出大的彩色圆

              smallCircle.drawGp(); //画出小的无彩圆

       }//end play()

      

       public static void main(String[] args)

       {

              BridgePattern bp = new BridgePattern();

              bp.play();

       }//end main(...)

 

}//end class BridgePattern

这样我们完成了Bridge模式的实现。在整个的学习过程中,我们所要具备的知识是,类的继承、多态。最重要的是要理解GoF给出的定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

下面是Bridge模式的UML图(以我们给出的例子为例):

 

 

 

适用性:(参考《设计模式》第101页)

l         你不希望在抽象和它的实现部分之间有一个固定的邦定关系。

l         类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这是的Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。

l         对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。

Bridge模式的关键特征:

l         意图:将一组实现部分从另一组使用他们的对象中分离出来。

l         问题:一个抽象类的派生类必须使用多种实现部分,但又不能引起类数量的爆炸。

l         解决方案:为所有的实现部分定义一个接口,让抽象类的所有派生类使用这个接口。

l         参与者与协作者:Abstraction为正在实现的对象定义接口。Implementor为特定的实现部分类定义接口。Abstraction的派生类使用Implementor的派生类,而不必知道自己使用的特定ConcreteImplementor

l         效果:“实现部分与使用它的对象的分离”增加了灵活性。客户对象不需要了解实现问题。

l         实现:将实现部分封装在一个抽象类中;在被实现的抽象部分基类中包含一个实现部分基类的句柄。

原创粉丝点击