设计模式——结构型——桥接模式

处理多维度变化

在正式介绍桥接模式之前,我先跟大家谈谈两种常见文具的区别,它们是毛笔和蜡笔。假如我们需要大中小3种型号的画笔,能够绘制12种不同的颜色,如果使用蜡笔,需要准备3×12 = 36支,但如果使用毛笔的话,只需要提供3种型号的毛笔,外加12个颜料盒即可,涉及到的对象个数仅为 3 + 12 = 15,远小于36,却能实现与36支蜡笔同样的功能。如果增加一种新型号的画笔,并且也需要具有12种颜色,对应的蜡笔需增加12支,而毛笔只需增加一支。为什么会这样呢?通过分析我们可以得知:在蜡笔中,颜色和型号两个不同的变化维度(即两个不同的变化原因)融合在一起,无论是对颜色进行扩展还是对型号进行扩展都势必会影响另一个维度;但在毛笔中,颜色和型号实现了分离,增加新的颜色或者型号对另一方都没有任何影响。如果使用软件工程中的术语,我们可以认为在蜡笔中颜色和型号之间存在较强的耦合性,而毛笔很好地将二者解耦,使用起来非常灵活,扩展也更为方便。在软件开发中,我们也提供了一种设计模式来处理与画笔类似的具有多变化维度的情况,即本章将要介绍的桥接模式。

 在开始学java的时候老师讲到继承的时候,总是喜欢用一个例子来讲解,那就是画图,这里有一个画笔,可以画正方形、长方形、圆形(这个大家都知道怎么做吧,我就不解释了)。但是现在我们需要给这些形状进行上色,这里有三种颜色:白色、灰色、黑色。这里我们可以画出3*3=9中图形:白色正方形、白色长方形、白色圆形。。。。。。到这里了我们几乎到知道了这里存在两种解决方案:

      方案一:为每种形状都提供各种颜色的版本。

      方案二:根据实际需要对颜色和形状进行组合。

      我们我们采用方案一来实现的话,我们是不是也可以这样来理解呢?为每种颜色都提供各种形状的版本呢?这个是完全的可以的。如下:

1111

  

      对于中两个图形,我们都会很清楚这样一个问题:加入我们添加椭圆,我们是不是又要增加三种颜色呢?假如我们在增加一个绿色,我们就要增加其四种形状了,继续加。继续加……每次增加都会增加若干个类(如果增加颜色则会增加形状个数个类,若增加形状则会增加颜色个数个类),这样的情况我想每个程序员都不会想要吧!那么我们看方案二。

      方案二所提供的就是解决方法是:提供两个父类一个是颜色、一个形状,颜色父类和形状父类两个类都包含了相应的子类,然后根据需要对颜色和形状进行组合。

33333

 

      对于有几个变化的维度,我们一般采用方案二来实现,这样除了减少系统中的类个数,也利于系统扩展。对于方案二的应用我们称之为桥接模式。

4444

 模式定义

     桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。

      桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。

      将抽象部分与他的实现部分分离这句话不是很好理解,其实这并不是将抽象类与他的派生类分离,而是抽象类和它的派生类用来实现自己的对象。这样还是不能理解的话。我们就先来认清什么是抽象化,什么是实现化,什么是脱耦。

      抽象化其概念是将复杂物体的一个或几个特性抽出去而只注意其他特性的行动或过程。在面向对象就是将对象共同的性质抽取出去而形成类的过程。

      实现化:针对抽象化给出的具体实现。它和抽象化是一个互逆的过程,实现化是对抽象化事物的进一步具体化。

      脱耦:脱耦就是将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联,将两个角色之间的继承关系改为关联关系。

      对于那句话:将抽象部分与他的实现部分分离套用《大话设计模式》里面的就是实现系统可能有多个角度分类,每一种角度都可能变化,那么把这种多角度分类给分离出来让他们独立变化,减少他们之间耦合。

      桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。

模式结构

下图是桥接模式的UML结构图:

 

55555

 

      桥接模式主要包含如下几个角色:

      Abstraction:抽象类。 
      RefinedAbstraction:扩充抽象类。 
      Implementor:实现类接口。 
      ConcreteImplementor:具体实现类 。 

模式实现

  模式场景我们就采用哪个画图的。其UML结构图如下:

66666

// 首先是形状类:该类为一个抽象类,主要提供画形状的方法:Shape.java
public abstract class Shape {
    Color color;

    public void setColor(Color color) {
        this.color = color;
    }
    
    public abstract void draw();
}


public class Circle extends Shape{

    public void draw() {
        color.bepaint("正方形");
    }
}


public class Rectangle extends Shape{

    public void draw() {
        color.bepaint("长方形");
    }

}


public class Square extends Shape{

    public void draw() {
        color.bepaint("正方形");
    }

}


public interface Color {
    public void bepaint(String shape);
}


public class White implements Color{

    public void bepaint(String shape) {
        System.out.println("白色的" + shape);
    }

}


public class Gray implements Color{

    public void bepaint(String shape) {
        System.out.println("灰色的" + shape);
    }
}


public class Black implements Color{

    public void bepaint(String shape) {
        System.out.println("黑色的" + shape);
    }
}


public class Client {
    public static void main(String[] args) {
        //白色
        Color white = new White();
        //正方形
        Shape square = new Square();
        //白色的正方形
        square.setColor(white);
        square.draw();
        
        //长方形
        Shape rectange = new Rectangle();
        rectange.setColor(white);
        rectange.draw();
    }
}

适配器模式与桥接模式的联用

        在软件开发中,适配器模式通常可以与桥接模式联合使用。适配器模式可以解决两个已有接口间不兼容问题,在这种情况下被适配的类往往是一个黑盒子,有时候我们不想也不能改变这个被适配的类,也不能控制其扩展。适配器模式通常用于现有系统与第三方产品功能的集成,采用增加适配器的方式将第三方类集成到系统中。桥接模式则不同,用户可以通过接口继承或类继承的方式来对系统进行扩展。

        桥接模式和适配器模式用于设计的不同阶段,桥接模式用于系统的初步设计,对于存在两个独立变化维度的类可以将其分为抽象化和实现化两个角色,使它们可以分别进行变化;而在初步设计完成之后,当发现系统与已有类无法协同工作时,可以采用适配器模式。但有时候在设计初期也需要考虑适配器模式,特别是那些涉及到大量第三方应用接口的情况。

        下面通过一个实例来说明适配器模式和桥接模式的联合使用:

        在某系统的报表处理模块中,需要将报表显示和数据采集分开,系统可以有多种报表显示方式也可以有多种数据采集方式,如可以从文本文件中读取数据,也可以从数据库中读取数据,还可以从Excel文件中获取数据。如果需要从Excel文件中获取数据,则需要调用与Excel相关的API,而这个API是现有系统所不具备的,该API由厂商提供。使用适配器模式和桥接模式设计该模块。

        在设计过程中,由于存在报表显示和数据采集两个独立变化的维度,因此可以使用桥接模式进行初步设计;为了使用Excel相关的API来进行数据采集则需要使用适配器模式。系统的完整设计中需要将两个模式联用,如图10-6所示:

 10.5 桥接模式总结

        桥接模式是设计Java虚拟机和实现JDBC等驱动程序的核心模式之一,应用较为广泛。在软件开发中如果一个类或一个系统有多个变化维度时,都可以尝试使用桥接模式对其进行设计。桥接模式为多维度变化的系统提供了一套完整的解决方案,并且降低了系统的复杂度。

1.主要优点

        桥接模式的主要优点如下:

        (1)分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。

        (2)在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。

        (3)桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。

2.主要缺点

        桥接模式的主要缺点如下:

        (1)桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。

        (2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。

3.适用场景

        在以下情况下可以考虑使用桥接模式:

        (1)如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。

        (2)“抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。

        (3)一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。

        (4)对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

 

练习

Sunny软件公司欲开发一个数据转换工具,可以将数据库中的数据转换成多种文件格式,例如txt、xml、pdf等格式,同时该工具需要支持多种不同的数据库。试使用桥接模式对其进行设计。

 

 

转载:https://www.cnblogs.com/lfxiao/p/6815760.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
包含3个实验,状态—观察者模式(某网上书店,用户购买书可以积分,积分达到一定值后可以升级为银会员、黄金会员等(用户等级有普通会员、银会员、黄金会员、钻石会员等),不同级别的会员购买书有不同的优惠。同时用户也可以用积分在网上书店兑换小礼品购书券),组合观察者模式(某会议管理系统的“会议通知发送”模块说明如下: (1)行政管理人员可以给某个或某些员工(Employee)发送会议通知,比如周六要通知员工A和员工B加班,该系统就会向员工A和B发通知,如果周日某个部门要整体加班,该系统会给某个部门(Department)发送通知,部门里面的每个员工都会收到加班通知。 (2)如果员工或者部门希望能够收到会议通知,必须先注册到一个会议列表(MeetingList)中,在发送通知时,系统将逐个将会议通知发送给注册用户(User)),建造者—工厂方法—状态模式(联机游戏中每一个游戏人物角色都需要提供一个完整的角色造型,包括人物造型(body)、服装(costume)、武器(weapon)等,武器主要有AK47冲锋枪、狙击枪和手枪,不同的武器外观、使用方法和杀伤力不同,玩家可以使用不同的武器,而且随着游戏的升级,还可以增加新的武器,无需对现有系统做太多修改。同时游戏角色存在3中不同的状态,如正常状态、暂停状态、阵亡状态等,在不同的状态下角色的行为不同(暂停、开始游戏、射击、移动、被攻击),并且能够在不同状态下转换。使用三种模式完成该游戏角色的设计。)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值