码迷,mamicode.com
首页 > 其他好文 > 详细

桥梁模式

时间:2015-08-25 19:10:58      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:

桥梁模式的用意是“将抽象化与实现化脱耦,使得二者可以独立地变化”。

所谓强关联,就是在编译时期已经确定的,无法在运行时期动态改变的关联;所谓弱关联,就是可以动态地确定并且可以在运行时期动态的改变的关联。在Java语言中,继承关系是强关联,而聚合关系是弱关联。

桥梁模式所涉及的角色有:

  • 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
  • 修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
  • 实现化(Implementor)角色:这个角色给出实现化角色的接口,但是不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
  • 具体实现化(Concrete Implementor)角色:这个角色给出实现化角色接口的具体实现。
/**
 * 抽象化角色
 */
public  abstract class Abstraction
{
    protected Implementor imp;
    /*
    * 某个商业方法
    * */
    public void operation()
    {
        imp.operationImp();
    }

 }

 

/**
 * 修正抽象化角色
 */
public class RefinedAbstraction extends Abstraction
{
    /*
    * 某个商业方法在修正抽象化角色的实现
    * */
    public void operation()
    {
        //code
    }
 }

 

/**
 * 抽象实现化角色
 */
public abstract class Implementor
{
    /*
    * 某个商业化方法的实现化声明
    * */
    public abstract void operationImp();
 }

 

/**
 * 具体实现化角色
 */
public class ConcreteImplementorA extends Implementor
{
    /*
    * 某个商业方法的实现化实现
    * */
    public void operationImp()
    {
        System.out.println("Do Something");
    }
 }

 这样讲起来还是很抽象,下面由一个具体的例子讲起:

例子:空中巴士(Airbus)、波音(Boeing)和麦道(McDonell-Douglas)都是飞机制造商,他们都生产载客飞机(Passenger Plane)和载货飞机(Cargo Plane)。现在需要设计一个系统,描述这些飞机制造商以及它们所制造的飞机种类。

设计方案一

首先,系统是关于飞机的,因此可以设计一个总的飞机接口,不妨叫做Airplane。其他所有的飞机都是这个总接口的子接口或者具体实现。下面是设计方案的设计图:

技术分享

在这个设计中,出现了两个子接口,分别表示客机和货机。所有的具体飞机又继承自Airbus,Boeing和MD等超类。这样一来,每一个具体飞机都带有两个超类型:飞机制造商类型,客、货机类型。

这样一来,一旦出现下面的情况,系统的设计就不可避免的需要修改:

  • 需要引进新的飞机制造商
  • 需要引进新的飞机类型

显然,在这个系统设计里面,过多地使用了继承关系。由于继承关系是一种静态的关联,因此很多涉及到这个关系的改变都会导致代码的修改。

改变这一局面的办法就是放弃继承关系,通过动态的委派改进系统的设计。

设计二

要克服第一个设计方案的缺点,可以使用桥梁模式这一锐利武器。

使用桥梁模式的关键在于准确地找出这个系统的抽象化角色和具体化角色。从系统所面对的问题不难看出,代表飞机的抽象化的是它的类型,也就是“客机”或者“货机”;而代表飞机的实现化的则是飞机制造商。

因此,可以给出一个更具有灵活性的设计,这个使用了桥梁模式而做的新设计如下图所示。

技术分享

在上图的设计中,客机和货机经过一个飞机的“转世”桥梁,可以分别“投胎”到空中巴士、波音和麦道等飞机制造商那里,“出生”为不同牌子的飞机。

由于这个“转世”桥梁实际上是一个聚合关系,因此可以动态地变化。所以如果系统需要加入新的飞机种类或者飞机制造商的话,已有的各个角色不必改变,需要改变的仅仅是一个多态性的聚合关系。

下面给出示意性的源代码:

/**
 * Airplane扮演抽象化角色,它声明出所有修正抽象化角色所需的接口
 */
public abstract class Airplane
{
    public abstract void fly();
    protected AirplaneMaker airplaneMaker;
    public Airplane(AirplaneMaker airplaneMaker)
    {
        this.airplaneMaker=airplaneMaker;
    }
}

 

/**
 * 载货飞机作为飞机的另一个种类,也属于修正抽象化角色
 */
public class CargoPlane extends Airplane
{
    public CargoPlane(AirplaneMaker airplaneMaker)
    {
        super(airplaneMaker);
    }
    @Override
    public void fly() {
        System.out.println("运货飞机");
    }
}

/**
 * 载客飞机作为飞机的种类,属于修正抽象化角色
 */
public class PassengerPlane extends Airplane
{
    public PassengerPlane(AirplaneMaker airplaneMaker)
    {
        super(airplaneMaker);
    }
    @Override
    public void fly() {
        System.out.println("载人飞机");
    }
}

 

/**
 * 该类扮演实现化角色
 */
public abstract class AirplaneMaker
{
    public abstract void produce();
}

 

/**
 * 具体实现化角色
 */
public class Airbus extends AirplaneMaker
{
    @Override
    public void produce() {
        System.out.println("空中客车制造");
    }
}
/**
 * 具体实现化角色
 */
public class Boeing extends AirplaneMaker
{
    @Override
    public void produce() {
        System.out.println("波音制造");
    }
}

/**
 * 具体实现化角色
 */
public class MD extends AirplaneMaker
{
    @Override
    public void produce() {
        System.out.println("麦道出品");
    }
}

 现在,如果需要增加新的飞机制造商,或者新的飞机种类的话,只需要向系统引进一个新的修正抽象化角色,或者一个新的具体实现角色就可以了。

一个好的设计通常没有多于两层的继承等级结构。或者说,如果出现两个以上的变化因素,就需要找出哪一个因素是静态的,可以使用继承关系;哪一个是动态的,必须使用聚合关系。

在这个飞机制造系统中,飞机的种类和制造商代表两个不同的变化因素,而这两个变化因素需要独立地变化,按照对变化的封装原则,他们应该被封装到继承的等级结构中。而这两个等级结构之间应当选择使用聚合关系,避免出现静态的强耦合关系,这就导致了桥梁模式的设计方案。

什么情况下使用桥梁模式:

  • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
  • 设计要求实现化角色的任何改变不影响客户端,或者说实现化角色的改变对客户端是完全透明的。
  • 一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
  • 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。

桥梁模式

标签:

原文地址:http://www.cnblogs.com/xtsylc/p/4755979.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!