桥(Bridge)模式

Bridge定义:将抽象和行为划分开来,各自独立,但能动态的结合。

为什么使用桥模式

通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以下两种:

    • 这多个具体实现之间恰好是并列的,如前面举例,打桩,有两个concrete class:方形桩和圆形桩;这两个形状上的桩是并列的,没有概念上的重复,那么我们只要使用继承就可以了。实际应用上,常常有可能在这多个concrete class之间有概念上重叠。那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口,分别放置抽象和行为。
      例如,一杯咖啡为例,有中杯和大杯之分,同时还有加奶 不加奶之分。如果用单纯的继承,这四个具体实现(中杯 大杯 加奶 不加奶)之间有概念重叠,因为有中杯加奶,也有中杯不加奶,如果再在中杯这一层再实现两个继承,很显然混乱,扩展性极差。那我们使用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. 中杯加奶中杯不加奶大杯加奶大杯不加奶
        看看是如何动态结合的,在使用之前,我们做个准备工作,设计一个单态类(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是该模式的关键。

      2.  实例2.我们假设有一座桥,桥左边为A,桥右边为B,A有A1,A2,A3等,表示桥左边的三个不同地方,B有B1,B2,B3等,表示桥右边的三个不同地方,假设我们要从桥左侧A出发到桥的右侧B,我们可以有多重方案,A1到B1,A1到B2,A1到B3,A2到B1...等等,以此为例

        桥接口:Qiao

        1 public interface Qiao {
        2     //目的地B
        3     void targetAreaB();
        4 }

        目的地B1,B2,B3:

         1 /**
         2  * 目的地B1
         3  */
         4 public class AreaB1 implements Qiao {
         5
         6     @Override
         7     public void targetAreaB() {
         8         System.out.println("我要去B1");
         9     }
        10
        11 }
        12
        13 /**
        14  * 目的地B2
        15  */
        16 public class AreaB2 implements Qiao {
        17
        18     @Override
        19     public void targetAreaB() {
        20         System.out.println("我要去B2");
        21     }
        22
        23 }
        24
        25 /**
        26  * 目的地B3
        27  */
        28 public class AreaB3 implements Qiao {
        29
        30     @Override
        31     public void targetAreaB() {
        32         System.out.println("我要去B3");
        33     }
        34
        35 }

        抽象来源地A:AreaA

        1 public abstract class AreaA {
        2     //引用桥接口
        3     Qiao qiao;
        4     //来源地
        5     abstract void fromAreaA();
        6 }

        来源地A1,A2,A3:

         1 /**
         2  * 来源地A1
         3  */
         4 public class AreaA1 extends AreaA {
         5
         6     @Override
         7     void fromAreaA() {
         8         System.out.println("我来自A1");
         9     }
        10
        11 }
        12
        13 /**
        14  * 来源地A2
        15  */
        16 public class AreaA2 extends AreaA {
        17
        18     @Override
        19     void fromAreaA() {
        20         System.out.println("我来自A2");
        21     }
        22
        23 }
        24
        25 /**
        26  * 来源地A3
        27  */
        28 public class AreaA3 extends AreaA {
        29
        30     @Override
        31     void fromAreaA() {
        32         System.out.println("我来自A3");
        33     }
        34
        35 }

        测试类:Clienter

        1 public class Clienter {
        2     public static void main(String[] args) {
        3         AreaA a = new AreaA2();
        4         a.qiao = new AreaB3();
        5         a.fromAreaA();
        6         a.qiao.targetAreaB();
        7     }
        8 }

        运行结果:

        我来自A2
        我要去B3

          如何,只要你认真看完了实例,你就明白了这种模式的好处,现在我们要添加来源地和目的地,只要继续继承AreaA和实现Qiao即可,之前我所说的绑定,正式此处将桥与目的地绑定在一起,使用一个接口完成。

          其实要完成桥接模式,注意点并不多,重在理解模式的使用场景。

          注意点:

            1、定义一个桥接口,使其与一方绑定,这一方的扩展全部使用实现桥接口的方式。

            2、定义一个抽象类,来表示另一方,在这个抽象类内部要引入桥接口,而这一方的扩展全部使用继承该抽象类的方式。

          其实我们可以发现桥接模式应对的场景有方向性的,桥绑定的一方都是被调用者,属于被动方,抽象方属于主动方。

          其实我的JDK提供的JDBC数据库访问接口API正是经典的桥接模式的实现者,接口内部可以通过实现接口来扩展针对不同数据库的具体实现来进行扩展,而对外的仅仅只是一个统一的接口调用,调用方过于抽象,可以将其看做每一个JDBC调用程序(这是真实实物,当然不存在抽象)

          下面来理解一下概念:

          桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

          这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

          理解:此处抽象化与实现化分别指代实例中的双方,而且实现化对应目的地方(通过实现桥接口进行扩展),抽象方对应来源地方(通过继承抽象类来进行扩展),如果我们不使用桥接模式,我们会怎么想实现这个实例呢?很简单,我们分别定义来源地A1、A2、A3类和目的地B1、B2、B3,然后具体的实现就是,A1到B1一个类,A1到B2一个类,等,如果我们要扩展了A和B ,要直接增加An类和Bn类,如此编写不说类内部重复性代码多,而且还会导致类结构的急剧膨胀,最重要的是,在通过继承实现路径的时候,会造成双方耦合性增大,而这又进一步加剧了扩展的复杂性。使用桥结构模式可以很好地规避这些问题:重在解耦。

时间: 2024-12-25 02:12:59

桥(Bridge)模式的相关文章

Java桥模式(Bridge模式)

Bridge定义:将抽象和行为划分开来,各自独立,但能动态的结合. 为什么使用桥模式 通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以下两种: 这多个具体实现之间恰好是并列的,如前面举例,打桩,有两个concrete class:方形桩和圆形桩:这两个形状上的桩是并列的,没有概念上的重复,那么我们只要使用继承就可以了. 实际应用上,常常有可能在这多个concrete class之间有概念上重叠.那么需要我们把抽象共同部分和行为共同

设计模式(六)桥连模式Bridge(结构型)

1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度? 例子1:设想如果要绘制矩形.圆形.椭圆.正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色.绿色.蓝色等,此时至少有如下两种设计方案: •第一种设计方案是为每一种形状都提供一套各种颜色的版本. •第二种设计方案是根据实际需要对形状和颜色进行组合. 方案1: 方案2: 对

设计模式之:桥连接模式

支持原创: http://blog.csdn.net/hguisu/article/details/7529194 1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度? 例子1:设想如果要绘制矩形.圆形.椭圆.正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色.绿色.蓝色等,此时至少有如下两种设计方案: •第一种设计方案是

C++设计模式实现--桥接(Bridge)模式

一. 举例 N年前: 计算机最先出来时,软件和硬件是一绑在一起的,比如IBM出了一台电脑,上面有一个定制的系统,假如叫 IBM_Win,这个IBM_Win系统当然不能在HP电脑上运行,同样HP出的HP_Win系统也不能运行在IBM上. 这时如果有一家新公司Apple出了一台新电脑,那么这个公司也要开发自己的系统 Apple_Win,Apple_Linux. 其实,上面几家公司开发的软件和硬件在很多地方都有相似之处,如果每家公司都做自己的系统,这意味着资源和人员的极大浪费. 这时,无论出现新的系统

Bridge 模式

Bridge 模式将抽象和行为划分开来,各自独立,但能动态的结合.在面向对象设计的基本概念中,对象这个概念实际是由属性和行为两个部分组成的,属性我们可以认为是一种静止的,是一种抽象,一般情况下,行为是包含在一个对象中,但是,在有的情况下,我们需要将这些行为也进行归类,形成一个总的行为接口,这就是桥模式的用处. 1 ///////////////Abstraction.h///////////// 2 #pragma once 3 class AbstractionImp ; 4 class Ab

Structual设计--Bridge模式

1.意图 将抽象部分与它的实现部分分离,使他们都可以独立地变化. 2.别名 Handle/Body 3.动机 当一个抽象对象可能有多个实现时,通常用继承来协调它们.抽象类定义对该抽象的接口,而具体的子类则用不同方式加以实现.但是此方法有时不够灵活.继承机制将抽象部分与它的实现部分固定在一起,使得难以对抽象部分和实现部分独立的进行修改.扩充和重用. 4.适用性 以下情况使用Bridge模式: 你不希望在抽象和它的实现部分之间有一个固定的绑定关系.例如这种情况可能是因为,在程序运行时刻实现部分应可以

Java 实现桥接(Bridge)模式

类图: /** * 手机壳.套 * @author stone * */ public abstract class BaseCellphoneShell { public abstract void mapping();//对应匹配哪种手机 } /** * 手机,桥接了 手机壳BaseCellphoneShell * @author stone */ public abstract class BaseCellphone { private BaseCellphoneShell shell;

Bridge模式

Bridge模式 Bridge模式 在面向对象的开发过程中,要做到2点:1.高内聚(cohesion),2.松耦合(coupling).但是在实际开发过程中难以把握,例如会遇到这样的问题: 1)客户给了一个需求,之后我们用一个类A来实现. 2)客户的需求有了变化,要用到2个算法来实现.于是我们通过定义一个抽象基类A,在用两个具体类A1和A2实现这两个算法. 3)客户需求又有了变化,要求在2个操作系统上实现.我们再抽象一个层次,不同操作系统抽象为A0和A1,每个操作系统上有2个算法,在实现为A00

设计模式之桥接模式(Bridge模式)

我想大家小时候都有用蜡笔画画的经历吧.红红绿绿的蜡笔一大盒,根据想象描绘出格式图样.而毛笔下的国画更是工笔写意,各展风采.而今天我们的故事从蜡笔与毛笔说起. 设想要绘制一幅图画,蓝天.白云.绿树.小鸟,如果画面尺寸很大,那么用蜡笔绘制就会遇到点麻烦.毕竟细细的蜡笔要涂出一片蓝天,是有些麻烦.如果有可能,最好有套大号蜡笔,粗粗的蜡笔很快能涂抹完成.至于色彩吗,最好每种颜色来支粗的,除了蓝天还有绿地呢.这样,如果一套12种颜色的蜡笔,我们需要两套24支,同种颜色的一粗一细.呵呵,画还没画,开始做梦了