posts - 73,  comments - 55,  trackbacks - 0

Bridge模式的目的:把抽象部分和行为部分分离,使它们都能独立变化。

任何事物对象都有抽象和行为之分,例如人,人是一种抽象,人分男人和女人等;人有行为,行为也有各种具体表现,所以,“人”与“人的行为”两个概念也反映了抽象和行为之分。

在面向对象设计的基本概念中,对象这个概念实际是由属性和行为两个部分组成的,属性我们可以认为是一种静止的,是一种抽象,一般情况下,行为是包含在一个对象中,但是,在有的情况下,我们需要将这些行为也进行归类,形成一个总的行为接口,这就是桥模式的用处。

总之,Bridge模式就是使抽象和行为分离,做到各自的独立发展,就是说抽象和行为各抽象出一个接口。当需要扩展行为或者抽象部分时,
只需扩展相应部分,而不用修改原来的结构。

例子一:
假如有个类DrawGraph有个画圆的接口,当然这个圆形可以用铅笔画,也可以用钢笔画。其中画圆是抽象部分,
用铅笔画和用钢笔画是行为部分。往往这个时候我们分别会定义铅笔类PencilDraw,钢笔类PenDraw来实现Draw,
这样就使得抽象部分和行为部分固定的捆绑在一起,扩展性不强。假如要动态增加一个用粉笔画的行为和一个画方形的抽象部分,
就必然要新定义一个ChalkDraw类,DrawGraph类里增加drawRectangle接口。显然这是很麻烦的。

Bridge模式是这样实现的:
//抽象部分
public abstract class DrawGraph {

 private ToolDraw toolDraw;
 public void setToolDraw(){
  this.toolDraw = ToolDrawSingleton.getToolDraw();//用Singleton模式来选工具。
 }
 
 public ToolDraw getToolDraw(){
  return toolDraw;
 }
 
 public abstract void draw();
}

//画圆
public class DrawCircle implements DrawGraph{
 public DrawCircle(){
  setToolDraw();
 }
 public void draw(){
  System.out.pritnln(toolDraw.getName() + " draw circle");
 }
}

//画矩形
public class DrawRectangle implements DrawGraph{
 public DrawRectangle(){
  setToolDraw();
 }
 public void draw(){
  System.out.pritnln(toolDraw.getName() + " draw rectangle");
 }
}

//行为部分
public abstract class ToolDraw{
 public abstract String getName();
 public abstract void drawWithTool();
}

//铅笔
public class PencilDraw implements ToolDraw{
 private final static String name = "Pencil";
 
 public static String getName(){
  return name;
 }
 
 public void drawWithTool(){
  System.out.println("Draw with Pencil.");
 }
}

//钢笔
public class PenDraw implements ToolDraw{
 private final static String name = "Pen";
 
 public String getName(){
  return name;
 }
 
 public void drawWithTool(){
  System.out.println("Draw with Pen.");
 }
}

//粉笔
public class ChalkDraw implements ToolDraw{
 private final static String name = "Chalk";
 
 public String getName(){
  return name;
 }
 
 public void drawWithTool(){
  System.out.println("Draw with Chalk.");
 }
}

做一个Singleton类来联系抽象和行为。通过此类来选工具
public class ToolDrawSingleton{
 private static ToolDraw toolDraw;
 
 public ToolDrawSingleton(ToolDraw toolDraw){
  this.toolDraw = toolDraw
 }
 public static ToolDraw getToolDraw(){
  return toolDraw;
 }
}

假如我们现在要用粉笔来画一个方形,一个圆形:
//取得工具
ToolDrawSingleton tool = new ToolDrawSingleton(new ChalkDraw());
//画方形
DrawGraph drawRectangle = new DrawRectangle();
drawRectangle.draw();
//画圆形
drawRectangle = new DrawCircle();
drawRectangle.draw();

例子二:
例如,一杯咖啡为例,子类实现类为四个:中杯加奶、大杯加奶、 中杯不加奶、大杯不加奶。

但是,我们注意到:上面四个子类中有概念重叠,可从另外一个角度进行考虑,这四个类实际是两个角色的组合:抽象 和行为,其中抽象为:中杯和大杯;行为为:加奶 不加奶(如加橙汁 加苹果汁).

实现四个子类在抽象和行为之间发生了固定的绑定关系,如果以后动态增加加葡萄汁的行为,就必须再增加两个类:中杯加葡萄汁和大杯加葡萄汁。显然混乱,扩展性极差。

那我们从分离抽象和行为的角度,使用Bridge模式来实现。

如何实现?
以上面提到的咖啡 为例. 我们原来打算只设计一个接口(抽象类),使用Bridge模式后,我们需要将抽象和行为分开,加奶和不加奶属于行为,我们将它们抽象成一个专门的行为接口.

先看看抽象部分的接口代码:

public abstract class Coffee
{
  CoffeeImp coffeeImp;

  public void setCoffeeImp() {
    this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();
  }

  public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}

  public abstract void pourCoffee();
}

其中CoffeeImp 是加不加奶的行为接口,看其代码如下:

public abstract class CoffeeImp
{
  public abstract void pourCoffeeImp();
}

现在我们有了两个抽象类,下面我们分别对其进行继承,实现concrete class:

//中杯
public class MediumCoffee extends Coffee
{
  public MediumCoffee() {setCoffeeImp();}

  public void pourCoffee()
  {
    CoffeeImp coffeeImp = this.getCoffeeImp();
    //我们以重复次数来说明是冲中杯还是大杯 ,重复2次是中杯
    for (int i = 0; i < 2; i++)
    {

      coffeeImp.pourCoffeeImp();
    }
  
  }
}

//大杯
public class SuperSizeCoffee extends Coffee
{
  public SuperSizeCoffee() {setCoffeeImp();}

  public void pourCoffee()
  {
    CoffeeImp coffeeImp = this.getCoffeeImp();
    //我们以重复次数来说明是冲中杯还是大杯 ,重复5次是大杯
    for (int i = 0; i < 5; i++)
    {

      coffeeImp.pourCoffeeImp();
    }
  
  }
}

上面分别是中杯和大杯的具体实现.下面再对行为CoffeeImp进行继承:

//加奶
public class MilkCoffeeImp extends CoffeeImp
{
  MilkCoffeeImp() {}

  public void pourCoffeeImp()
  {
    System.out.println("加了美味的牛奶");
  }
}

//不加奶
public class FragrantCoffeeImp extends CoffeeImp
{
  FragrantCoffeeImp() {}

  public void pourCoffeeImp()
  {
    System.out.println("什么也没加,清香");
  }
}

Bridge模式的基本框架我们已经搭好了,别忘记定义中还有一句:动态结合,我们现在可以喝到至少四种咖啡:
1.中杯加奶
2.中杯不加奶
3.大杯加奶
4.大杯不加奶

看看是如何动态结合的,在使用之前,我们做个准备工作,设计一个单态类(Singleton)用来hold当前的CoffeeImp:

public class CoffeeImpSingleton
{
  private static CoffeeImp coffeeImp;

  public CoffeeImpSingleton(CoffeeImp coffeeImpIn)
   {this.coffeeImp = coffeeImpIn;}

  public static CoffeeImp getTheCoffeeImp()
  {
    return coffeeImp;
  }
}

看看中杯加奶 和大杯加奶 是怎么出来的:

//拿出牛奶
CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp());

//中杯加奶
MediumCoffee mediumCoffee = new MediumCoffee();
mediumCoffee.pourCoffee();

//大杯加奶
SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();
superSizeCoffee.pourCoffee();

注意: Bridge模式的执行类如CoffeeImp和Coffee是一对一的关系, 正确创建CoffeeImp是该模式的关键。

posted on 2006-07-10 17:13 保尔任 阅读(398) 评论(0)  编辑  收藏 所属分类: Design Patten

只有注册用户登录后才能发表评论。


网站导航:
 

<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

常用链接

留言簿(4)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜