首页 > 编程语言 >Python实现软件设计模式10:装饰器模式 Decorator Pattern

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

时间:2024-02-08 18:55:05浏览次数:38  
标签:__ 10 Python 子类 self 模式 对象 装饰 def

概念

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

结构

角色

  • 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();

标签:__,10,Python,子类,self,模式,对象,装饰,def
From: https://www.cnblogs.com/Higgerw/p/18012032

相关文章

  • ABC 310
    E\(dp[i][j]\)表示前\(i\)个里有多少个后缀答案为\(j\)。\(if(c[i]=='0')\{\)\(dp[i][0]=1;\)\(dp[i][1]=dp[i-1][0]+dp[i-1][1];\)\(\}\)\(else\{\)\(dp[i][0]=dp[i-1][1];\)\(dp[i][1]=1+dp[i-1][0];\)\(\}\)F......
  • Python调用USB摄像头
    1.硬件连接方式USB摄像头通过USB接口连接到PC。2.使用说明使用的是python3.11.5,程序可以在PyCharm中直接运行。运行后,即可打开一个实时预览窗口,显示摄像头画面。在预览窗口中,按键盘上的‘q’(quit)退出预览,按‘p’(takephoto)拍照。拍照的图片,保存在工程根目录下,名字形如“cv2......
  • python turtle 递归绘制树
    运行效果代码importturtleastimportrandomasrc=["pink","green","lightgreen","orange","red","purple"]defdrawStar(l):t.begin_fill()foriinrange(5):t.forward(l)......
  • 0-100之间的奇数和偶数的和
    需求0-100之间的奇数和偶数的和代码实现packagecom.jichu.struct;publicclassForDemo01{publicstaticvoidmain(String[]args){//0-100之间的奇数和偶数的和intodd=0;inteven=0;for(inti=0;i<=100;i++){......
  • 用while或for循环输出1-1000之间能被5整除的数,并且每行输出3个
    需求用while或for循环输出1-1000之间能被5整除的数,并且每行输出3个代码实现packagecom.jichu.struct;publicclassForDemo02{publicstaticvoidmain(String[]args){//用while或for循环输出1-1000之间能被5整除的数,并且每行输出3个的需求for(......
  • 【Python】基于动态残差学习的堆叠式LSTM模型和传统BP在股票预测中的应用
    1.前言本论文探讨了长短时记忆网络(LSTM)和反向传播神经网络(BP)在股票价格预测中的应用。首先,我们介绍了LSTM和BP在时间序列预测中的基本原理和应用背景。通过对比分析两者的优缺点,我们选择了LSTM作为基础模型,因其能够有效处理时间序列数据中的长期依赖关系,在基础LSTM模型的基础上,......
  • 设计模式-模板方法模式(Template Method Pattern)
    #模板方法模式(TemplateMethodPattern)-记忆关键字:模板方法-定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤-类型:行为型-![UML类图](./design-pattern.png)##1.涉及的角色1)Abstr......
  • 10_TIM编码器接口
    TIM编码器接口编码器接口简介正交编码器旋转编码器简介编码器接口基本结构工作模式实例(均不反相)实例(TI1反相)编码器接口测速选择接口和定时器接线图代码Encoder.c#include"stm32f10x.h"//DeviceheadervoidEncoder_Init(void){......
  • Python与anaconda的 pip 冲突
    Python与anaconda的pip冲突1.默认pipinstall会安装到Anaconda下假如我们想要安装到python目录下D:\Python\Python36\Lib\site-packages找到Anaconda安装目录:D:\Anaconda3\python.exe2.验证原生python3python3–mpip–-versionpython3–mpiplist#......
  • python版本管理工具pyenv常见用法
    安装Mac使用brew进行安装:brewupdatebrewinstallpyenv配置环境变量(以zsh为例):echo'exportPYENV_ROOT="$HOME/.pyenv"'>>~/.zshrcecho'[[-d$PYENV_ROOT/bin]]&&exportPATH="$PYENV_ROOT/bin:$PATH"'>&g......