Python实现软件设计模式10:装饰器模式 Decorator Pattern

概念

  • 是一种对象结构型模式
  • 可以在不改变一个对象本身功能的基础上给对象增加额外的新行为
  • 是一种用于替代继承的技术,他通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系
  • 引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩展原有类的功能
  • 以对客户透明的方式动态给一个对象附加上更多的责任
  • 可以再不需要创建更多子类的情况下,让对象得功能得以扩展

结构

角色

  • Component 抽象构件类:抽象接口,只声明通用方法
  • ConcreteComponent 具体构件类:实现了一些基本方法
  • Decorator 抽象装饰类:是所有装饰类的父类,同时是Component的子类,会关联(注入)一个Component类的子类对象
  • ConcreteDecorator 具体装饰类:扩展抽象装饰类,提供更多功能

透明装饰模式

  • 完全针对抽象编程,不该将对象声明为具体构件类型或具体装饰类型,应该全声明为抽象构件类型
  • 可以透明地使用装饰之前的对象和装饰之后的对象,无须关心其区别
  • 某个已装饰过的对象,可以继续注入另一个ConcreteDecorator,实现多层装饰
  • 无法单独调用addedBehavior()方法
    Java版本示例代码:
Component o,d1,d2; //全部使用抽象构件类型定义
o = new ConcreteComponent();
d1 = new ConcreteComponent(o);
d2 = new ConcreteComponent(d1);
d2.operation();  // 无法单独调用d2的addedBehaviour()方法

半透明(Semi-transparent)装饰模式

  • 可以给系统带来更多灵活性,设计简单,使用方便
  • 使用具体装饰类型来定义装饰后的对象,因此可以单独调用addedBehavior()方法
  • 缺点在于,不能实现对同一对象的多次装饰,而且需要有区别地对待装饰前、装饰后的对象
    Java版本示例代码:
Component c1;   // 使用抽象构件类型定义
c1 = new ConcreteComponent();
c1.operation();

ConcreteDecorator c2;   // 使用具体装饰类型定义
c2 = new ConcreteDecorator(c1);
c2.operation();
c2.adderBehaviour();    // 单独调用新增业务方法

Python实现

案例:变形金刚在变形前是汽车,可以在陆地上疾驰;当它变形成机器人之后可以在陆地上奔跑并向霸天虎开火;如果需要,可以变形成飞机,它除了可以在陆地上疾驰还可以在天空中飞翔。下面是该设计模式结构图:

from abc import ABC, abstractmethod

class Transform(ABC):
    @abstractmethod
    def move(self):
        pass

class Car(Transform):
    def __init__(self):
        print("变形金刚是一辆车!")

    def move(self):
        print("在陆地上移动!")

class Changer(Transform):       # 抽象装饰类 (变形)
    def __init__(self, trans : Transform) -> None:
        self.__transform = trans
    
    def move(self):
        self.__transform.move()

class Airplane(Changer):
    def __init__(self, trans: Transform) -> None:
        super().__init__(trans)
        print("变形成飞机!")
    
    def fly(self):
        print("在天空飞翔!")

class Robot(Changer):
    def __init__(self, trans: Transform) -> None:
        super().__init__(trans)
        print("变形成机器人!")
    
    def fire(self):
        print("向霸天虎开火!")

if __name__ == '__main__':
    '''
    半透明装饰方法
    '''
    camero = Car()  # 具体构件类
    camero.move()

    print("--------------")

    bumblebee = Airplane(camero)
    bumblebee.move()
    bumblebee.fly() # 调用到了具体装饰类Airplane中新增加的方法

    print("+++++++++++++++")
    
    # X = Robot(camero)
    # X.move()
    # X.fire() 

    X = Robot(bumblebee)
    X.move()
    X.fire()
    # X.fly()   半透明装饰模式只具有最后一次具体装饰类的功能、属性,会丧失中间层装饰类的功能、属性

装饰器模式总结

优点

  • 对于扩展一个对象的功能,装饰模式比集成更加灵活,不会导致类个数的急剧增加
  • 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以再运行时选择不同的具体装饰类,从而实现不同的行为
  • 可以对一个对象进行多次装饰
  • 具体构件类ConcreteComponent与具体装饰类ConcreteDecorator可以独立变化,用户可以根据需要增加新的具体构建类ConcreteComponent和具体装饰类ConcreteDecorator,且原有类库代码无需改变,符合开闭原则

应用场景

  • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
  • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

且听风吟

装饰模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。

下面代码是为 FileReader 增加缓冲区而采用的装饰类 BufferedReader 的例子:

BufferedReader in = new BufferedReader(new FileReader("filename.txt"));
String s = in.readLine();
posted @ 2024-02-08 18:48  爱吃砂糖橘的白龙  阅读(10)  评论(0编辑  收藏  举报