python设计模式-桥接模式&比较桥接模式和装饰模式的不同

产生桥接模式的动机:

假设这样一种情况:
我们有大中小型号的毛笔,有红蓝黑三种颜料。如果需要不同颜色,不同型号的毛笔有如下两种设计方法:

  1. 为每一种型号的毛笔都提供三种颜料的版本。
  2. 将毛笔和颜料分开,使用的时候自由组合。

针对第一种我们当下就需要红色颜料大号毛笔、蓝色颜料大号毛笔等九中型号,在之后的扩展中,每增加一个型号的毛笔就需要为其增加所有颜料的版本, 而每增加一种颜料也需要为所有的笔增添新的颜料类型。随着笔的类型和颜料种类的不断增长,其类数量的增加速度为O(n!) 我们需要维护庞大的种类集合。
而第二种我们将笔和颜料分开,就比如说准备大中小三种型号的毛笔,以及红蓝黑三种颜料,用的时候就拿笔区蘸一下颜料就可以,这样笔和颜料解耦,他们可以分开增加。其类的增加速度为O(n) 我们可以看出 O(n!)的增长速度远大于O(n)。

第一种方法在系统设计上我们采用的就是继承的方式。实现方式上有两种,一种就像我上面提到的只有一个抽象类,然后所有子类都是由这个抽象类里面派生出来了,还有一种代码编写方式就是提供毛笔抽象类和颜料抽象类 以及他们的派生子类,然后子类使用多继承分别继承他们,这种编写方式又一个问题就是在不支持多继承的语言中无法实现(例子请看我的 文章中的那一部分。)

第二种方法是采用组合关系的设计,其设计中也是将颜料和笔这两个变化分开,及分别由笔的抽象类派生出各种各样的笔和由颜料抽象类派生出的各种各样的颜料。但是将他们之间连接在一起的是关联关系方式(不懂的可以区我的这一篇文章看一下)。在结构型设计模式中大量使用这种关联关系来代替继承关系以实现解耦,为什么关联关系可以解耦呢?我认为主要有以下几点:

  1. 继承关系中,父类的修改会传播到子类中,容易造成子类的不稳定。
  2. 继承关系在代码编写阶段已经固定,但是使用关联关系,我们可以将他们之间的关系确定推迟到程序运行时,更加方便用户控制。比如使用配置文件来确定关联关系中的两个类的类型。
  3. 使用关联关系也可以减少代码的编写量,尤其是在变化的种类很多以及后期增加种类的时候。
  4. 使用关联关系在后期增加变化种类,不需要更改已经存在的类。满足开闭原则
  5. 使用关联关系也将功能分割,符合单一职责原则

桥接模式的定义:

桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

实现

使用继承方式的实现

UML类图

《python设计模式-桥接模式&比较桥接模式和装饰模式的不同》

python 代码

class BrushAbstraction(object):
    def __init__(self, size, color):
        self.paint = None
        self.__size = size
        self.__color = color

    def draw(self):
        print('Use {} {} brush draw'.format(self.__color, self.__size))


class BigBrushAbstration(BrushAbstraction):
    def __init__(self, color):
        super(BigBrushAbstration, self).__init__('Big', color)


class MiddleBrushAbstration(BrushAbstraction):
    def __init__(self, color):
        super(MiddleBrushAbstration, self).__init__('Middle', color)


class SmallBrushAbstration(BrushAbstraction):
    def __init__(self, color):
        super(SmallBrushAbstration, self).__init__('Small', color)


class RedBigBrushAbstration(BigBrushAbstration):
    def __init__(self):
        super(RedBigBrushAbstration, self).__init__('Red')


class BlueBigBrushAbstration(BigBrushAbstration):
    def __init__(self):
        super(BlueBigBrushAbstration, self).__init__('Blue')


class BlackBigBrushAbstration(BigBrushAbstration):
    def __init__(self):
        super(BlackBigBrushAbstration, self).__init__('Black')


class RedMiddleBrushAbstration(MiddleBrushAbstration):
    def __init__(self):
        super(RedMiddleBrushAbstration, self).__init__('Red')


class BlueMiddleBrushAbstration(MiddleBrushAbstration):
    def __init__(self):
        super(BlueMiddleBrushAbstration, self).__init__('Blue')


class BlackMiddleBrushAbstration(MiddleBrushAbstration):
    def __init__(self):
        super(BlackMiddleBrushAbstration, self).__init__('Black')


class RedSmallBrushAbstration(SmallBrushAbstration):
    def __init__(self):
        super(RedSmallBrushAbstration, self).__init__('Red')


class BlueSmallBrushAbstration(SmallBrushAbstration):
    def __init__(self):
        super(BlueSmallBrushAbstration, self).__init__('Blue')


class BlackSmallBrushAbstration(SmallBrushAbstration):
    def __init__(self):
        super(BlackSmallBrushAbstration, self).__init__('Black')


if __name__ == '__main__':
    blue_big_brush = BlueBigBrushAbstration()
    blue_big_brush.draw()

    black_big_brush = BlackBigBrushAbstration()
    black_big_brush.draw()

使用桥接模式重构后

UML类图

《python设计模式-桥接模式&比较桥接模式和装饰模式的不同》

代码

class BrushAbstraction(object):
    def __init__(self, size):
        self.paint = None
        self.__size = size

    def dip_paint(self, paint):
        self.paint = paint

    def draw(self):
        print('Use {} {} brush draw'.format(self.paint.color(), self.__size))


class BigBrushAbstration(BrushAbstraction):
    def __init__(self):
        super(BigBrushAbstration, self).__init__('Big')


class MiddleBrushAbstration(BrushAbstraction):
    def __init__(self):
        super(MiddleBrushAbstration, self).__init__('Middle')


class SmallBrushAbstration(BrushAbstraction):
    def __init__(self):
        super(SmallBrushAbstration, self).__init__('Small')


class PaintImplementer(object):
    def __init__(self, color):
        self.__color = color

    def color(self):
        return self.__color


class RedPaintImplementer(PaintImplementer):
    def __init__(self):
        super(RedPaintImplementer, self).__init__('Red')


class BluePaintImplementer(PaintImplementer):
    def __init__(self):
        super(BluePaintImplementer, self).__init__('Blue')


class BlackPaintImplementer(PaintImplementer):
    def __init__(self):
        super(BlackPaintImplementer, self).__init__('Black')


if __name__ == '__main__':
    big_bursh = BigBrushAbstration()
    big_bursh.dip_paint(BluePaintImplementer())
    big_bursh.draw()

    big_bursh.dip_paint(BlackPaintImplementer())
    big_bursh.draw()

代码分析

在上面的继承方式的实现中我们采用的是单继承,在我的python设计模式-装饰模式采用继承方式就是多继承。桥接模式有时类似多继承方法。不过桥接模式产生了很多不同的小对象而多继承方案产生了很多不同的小类。但是多继承方案违背了类的单一职责原则(即一个类只应该有一个变化的原因),其次多继承关系的确定在编码阶段就已经确定,无法灵活的扩展,还有就是很多语言是不支持多继承的。

桥接模式的优缺点

优点

  1. 分离了抽象接口与实现部分
  2. 提高系统可扩充性,在两个纬度中任意扩展,都不需对原系统进行修改。

缺点

桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。 – 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。

适用环境

  1. 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  2. 抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
  3. 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
  4. 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
  5. 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

桥接模式和装饰模式的区别

python设计模式-装饰模式

  1. 桥接模式和装饰模式都是通过将继承关系转换为关联关系从而减少系统中类的数量,降低系统的耦合性。
  2. 桥接模式是解决一个系统有多个变化维度的一种设计模式。其难点是如何将其中的抽象化与实现化分离(抽象化是指将一组复杂物体的一个或几个特征抽取出来形成共用部分,在面向对象的程序设计中就是将对象共同的性质抽取出去而形成类的过程。实现化是指给出抽象化中的具体实现,他是对抽象化的建进一步具体化)。使用关联关系在运行时设置不同的具体类来让同一个抽象对象表现出不同的行为。在整个过程中抽象化的类其实是不稳定的,不稳定指我们通过传入不同的实现类改变了抽象类本身的运行结果。
  3. 装饰器模式是解决如何给一个类动态增加职责的一种设计模式。装饰器模式通过将一个类中需要动态执行的方法抽取出来形成装饰类,通过关联关系来将职责的添加推迟到了程序运行时。如果程序支持反射还可以通过配置文件来灵活更改对象的功能。装饰器模式支持多层装饰,通过不同的组合可以实现不同的行为。在整个过程中被装饰对象是稳定的。因为装饰模式是在被装饰对象的前后增加功能,而不是改变被装饰对象本身的功能。具体的装饰类和被装饰类可以独立变化,用户根据需要动态的增加装饰类和被装饰类,并在调用的时候进行组合,无需更改之前的代码,符合开闭原则。
  4. 从实现上看桥接模式中抽象类只包含一个实现类的引用,实现对实现类的调用。而装饰模式中抽象装饰类继承构件抽类类,并且还包含一个对抽象构建的引用。
    原文作者:设计模式
    原文地址: https://segmentfault.com/a/1190000012184662
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注