装饰器设计模式是什么?什么是 Decorator 装饰器设计模式?Python 装饰器设计模式示例代码

news2024/10/2 22:30:27

什么是 Decorator 装饰器设计模式?

装饰器模式是一种结构型设计模式,它允许向现有对象动态地添加新功能,同时不改变其结构。这种模式实现了对对象的包装,称为装饰器,并且可以在运行时动态地添加、修改或删除对象的行为。

在这里插入图片描述

主要思想:

装饰器模式允许你通过将对象放入包含行为的特殊包装器对象中来为原始对象添加新功能,使得代码更灵活、可重用,并且遵循开放-封闭原则。

主要角色:

  1. Component(组件): 定义了一个对象接口,可以动态地为该对象添加职责。
  2. ConcreteComponent(具体组件): 实现了 Component 接口的具体对象,是被装饰的原始对象。
  3. Decorator(装饰器): 持有一个指向 Component 对象的引用,并定义一个与 Component 接口一致的接口。
  4. ConcreteDecorator(具体装饰器): 向组件添加新的功能。

在这里插入图片描述

工作流程:

  1. 创建一个 Component 接口以及其具体实现 ConcreteComponent。
  2. 创建一个装饰器类,实现与 Component 相同的接口,并持有一个 Component 对象作为其成员变量。
  3. 创建具体装饰器类,对装饰器类进行扩展,添加额外的功能。

优点:

  1. 灵活性和扩展性: 可以动态地向对象添加新的功能,而无需修改其结构。可以通过堆叠装饰器来组合不同的功能,实现更多的组合方式。

  2. 遵循开放-封闭原则: 可以在不修改现有代码的情况下,通过装饰器来扩展功能,遵循了开放-封闭原则,使得系统更易于扩展。

  3. 单一职责原则: 可以将不同的责任分配给不同的装饰器,使得每个装饰器只关注一个特定的功能,符合单一职责原则。

  4. 代码复用性: 装饰器可以被多个对象共享使用,提高了代码的复用性,避免了重复编写相似功能的代码。

缺点:

  1. 复杂性增加: 可能会导致类层次结构变得复杂,堆叠过多的装饰器可能会使代码难以理解和维护。

  2. 运行时影响: 在运行时动态地添加功能,可能会影响系统的性能,特别是堆叠过多的装饰器可能会增加函数调用的开销。

  3. 正确性和顺序: 装饰器的正确性和顺序是很重要的,装饰器的堆叠顺序可能会影响最终的结果,需要小心处理。

  4. 不适用所有情况: 装饰器并不适用于所有情况。有些情况可能会使用其他设计模式更为合适,需要根据具体情况进行选择。

总的来说,装饰器模式提供了一种灵活的方式来扩展对象的功能,但需要权衡其增加的复杂性和运行时的影响。在适当的情况下使用,能够有效地提高代码的可扩展性和可维护性。


Python 实现装饰器设计模式示例代码(一):

# Component 接口
class Coffee:
    def cost(self):
        pass

# ConcreteComponent
class SimpleCoffee(Coffee):
    def cost(self):
        return 5

# Decorator 装饰器类
class CoffeeDecorator(Coffee):
    def __init__(self, coffee):
        self._coffee = coffee

    def cost(self):
        return self._coffee.cost()

# ConcreteDecorator 具体装饰器类
class Milk(CoffeeDecorator):
    def cost(self):
        return self._coffee.cost() + 2

class Sugar(CoffeeDecorator):
    def cost(self):
        return self._coffee.cost() + 1

# 使用示例
coffee = SimpleCoffee()
print(coffee.cost())  # 输出:5

coffee_with_milk = Milk(coffee)
print(coffee_with_milk.cost())  # 输出:7

coffee_with_milk_and_sugar = Sugar(coffee_with_milk)
print(coffee_with_milk_and_sugar.cost())  # 输出:8

在这个示例中,Coffee 是组件接口,SimpleCoffee 是具体组件,CoffeeDecorator 是装饰器类,MilkSugar 是具体装饰器类。通过装饰器模式,可以动态地为咖啡对象添加不同的装饰(牛奶、糖),每个装饰器都可以增加价格。


Python 实现装饰器设计模式示例代码(二):

当处理网页生成时,可以使用装饰器模式来动态地添加不同的 HTML 样式和元素。

# Component 接口
class HTMLPage:
    def show(self):
        pass

# ConcreteComponent
class BasicHTMLPage(HTMLPage):
    def show(self):
        return "Basic HTML Page"

# Decorator 装饰器类
class HTMLDecorator(HTMLPage):
    def __init__(self, html_page):
        self._html_page = html_page

    def show(self):
        return self._html_page.show()

# ConcreteDecorator 具体装饰器类
class BoldDecorator(HTMLDecorator):
    def show(self):
        return f"<b>{self._html_page.show()}</b>"

class ItalicDecorator(HTMLDecorator):
    def show(self):
        return f"<i>{self._html_page.show()}</i>"

# 使用示例
basic_page = BasicHTMLPage()
print(basic_page.show())  # 输出:Basic HTML Page

bold_page = BoldDecorator(basic_page)
print(bold_page.show())  # 输出:<b>Basic HTML Page</b>

italic_bold_page = ItalicDecorator(bold_page)
print(italic_bold_page.show())  # 输出:<i><b>Basic HTML Page</b></i>

在这个示例中,HTMLPage 是组件接口,BasicHTMLPage 是具体组件,HTMLDecorator 是装饰器类,BoldDecoratorItalicDecorator 是具体装饰器类。通过装饰器模式,可以动态地为基本 HTML 页面添加不同的样式,比如加粗、斜体等。


使用装饰器设计模式时,需要注意哪些地方?

在使用装饰器设计模式时,需要留意以下几个方面:

  1. 继承关系: 装饰器模式通过继承实现,这可能导致类层次结构变得复杂。过多的装饰器可能会使代码难以理解和维护。

  2. 功能堆叠顺序: 装饰器的堆叠顺序很重要,可能会影响最终结果。确保装饰器按照正确的顺序应用,避免意外的行为。

  3. 适用性和灵活性: 装饰器模式并不适用于所有情况。在某些情况下,可能会使用其他模式更为合适,需要根据具体情况进行选择。

  4. 影响性能: 堆叠过多的装饰器可能会影响性能,特别是在对性能敏感的场景下。过多的装饰器会增加函数调用的开销。

  5. 单一职责原则: 确保每个装饰器只关注一个特定的功能。不要让装饰器变得过于复杂,应遵循单一职责原则。

  6. 可读性和维护性: 过多的装饰器可能会降低代码的可读性和维护性。建议在使用装饰器时保持代码简洁易懂。

  7. Python 特殊性: 在 Python 中,装饰器是一种语法糖,经常用于修饰函数。但使用装饰器时要注意其影响范围和作用域。

总的来说,装饰器模式是一种灵活且强大的模式,但需要谨慎使用,特别是在需要管理复杂装饰器堆叠和性能敏感的情况下。


本文就到这里了,感谢您的阅读 。别忘了点赞、收藏~ Thanks♪(・ω・)ノ 🍇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1241180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyTorch深度学习实战——人体姿态估计

PyTorch深度学习实战——人体姿态估计 0. 前言1. 人体姿态估计2. 使用 Detectron2 实现人体姿态估计相关链接 0. 前言 我们已经学习了如何执行实例分割&#xff0c;在本节中&#xff0c;我们将了解如何利用 Detectron2 对图像执行人体姿态估计&#xff0c;检测图像中人物的身体…

2023亚太杯数学建模A题思路 - 采果机器人的图像识别技术

# 1 赛题 问题A 采果机器人的图像识别技术 中国是世界上最大的苹果生产国&#xff0c;年产量约为3500万吨。与此同时&#xff0c;中国也是世 界上最大的苹果出口国&#xff0c;全球每两个苹果中就有一个&#xff0c;全球超过六分之一的苹果出口 自中国。中国提出了一带一路倡议…

【开源】基于Vue.js的民宿预定管理系统

项目编号&#xff1a; S 058 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S058&#xff0c;文末获取源码。} 项目编号&#xff1a;S058&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用例设计2.2 功能设计2.2.1 租客角色…

SpringBoot整合RabbitMQ中交换机的使用(完成消息的发送和接收案例)

系列文章目录 1.SpringBoot整合RabbitMQ并实现消息发送与接收 2. 解析JSON格式参数 & 修改对象的key 3. VUE整合Echarts实现简单的数据可视化 4. List&#xff1c;HashMap&#xff1c;String,String&#xff1e;&#xff1e;实现自定义字符串排序&#xff08;key排序、Val…

雷电模拟器打开指针位置无效果解决方法(开发者模式)

预期效果 1.打开文件所在位置 2.进入vms目录 3.新建一个名为debug的txt格式的文件 4.打开开发者模式里面指针位置的选项 5.重启模拟器 6.噔噔噔噔~

教你如何将Web项目部署到Linux中

文章目录 前言0. 什么是部署1. 调整代码达成一致2. 数据库建表3. 构建项目并打包4. 拷贝到 Tomcat 中5. 效果总结 前言 在我们完成了一个Web项目后, 我们该怎样将项目部署到 Linux 系统中呢? 本文就来简单讲解一下. 文章已部署本人的博客系统代码展开讲解. 关注收藏, 开始学…

【数据库】数据库中的备份与恢复,保障容灾时的数据一致性与完整性

数据库的备份机制 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定期…

postman定义公共函数这样写,测试组长直呼牛逼!!!

postman定义公共函数 在postman中&#xff0c;如下面的代码&#xff1a; 1、返回元素是否与预期值一致 var assertEqual(name,actual,expected)>{tests[${name}&#xff1a;实际结果&#xff1a; ${actual} &#xff0c; 期望结果&#xff1a;${expected}]actualexpected…

YOLO目标检测——卫星遥感多类别检测数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;卫星遥感目标检测数据集说明&#xff1a;卫星遥感多类别检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;含网球场、棒球场、篮球场、田径场、储罐、车辆、桥、飞机、船等类别标签说明&#xff1a;使用lableimg标…

Mysql中自增主键是如何工作的

自增主键的特点是当表中每新增一条记录时&#xff0c;主键值会根据自增步长自动叠加&#xff0c;通常会将自增步长设置1&#xff0c;也就是说自增主键值是连续的。那么MySQL自增主键值一定会连续吗&#xff1f;今天这篇文章就来说说这个问题&#xff0c;看看什么情况下自增主键…

灵活运用Vue 3中的setup函数—深入解析Composition API

新建项目&#xff0c;项目主入口为App.vue&#xff08;主组件&#xff09;&#xff0c;新建child.vue&#xff08;子组件&#xff09;。 1.1 setup 执行 时机问题 1.在主组件里引入子组件和ref&#xff1a; import {ref} from vue import child from ./components/child.vue2…

数据科学导论——数据预处理

第1关:引言-根深之树不怯风折,泉深之水不会涸竭 第2关:数据清理-查漏补缺 import numpy as np import pandas as pd import matplotlib.pyplot as plt def student():train = pd.read_csv(Task1/diabetes_null.csv, na_values=[#NAME?])train[Insulin] = train[Insulin].f…

【20年扬大真题】试写一算法在带头结点的单链表结构上实现线性表操作LENGTH(L)

【20年扬大真题】 试写一算法在带头结点的单链表结构上实现线性表操作LENGTH&#xff08;L&#xff09;。 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdbool.h> #include<malloc.h> //单链表定义 //链表结点 int A[10] { 1,2,3,4,5,6,…

Java生成一个区域内的经纬度随机点的方式

准备&#xff1a; 1、四个角点&#xff08;四个点确定一个框&#xff09; 2、想要细分程度 &#xff08;这里说的是经纬度&#xff0c;这里没有对经纬度做更细的区分&#xff09; 如&#xff1a;0.000001约等于0.1m&#xff0c;0.00001约等于1m&#xff0c;0.0001约等于10m 。。…

小黑子—Maven高级

Maven高级篇 二 小黑子的Maven高级篇学习1. 分模块开发1.1 分模块开发设计1.2 分模块开发实现1.2.1 抽取domain层1.2.2 抽取dao层 2. 依赖管理2.1 依赖传递2.2 可选依赖2.3 排除依赖 3. 继承与聚合3.1 聚合3.2 继承3.3 总结 4. 属性4.1 配置文件加载属性4.2 版本管理 5. 多环境…

浅谈JDK动态代理(上)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 到目前为止&#xff0c…

Java面向对象(高级)-- 类中属性赋值的位置及过程

文章目录 一、赋值顺序&#xff08;1&#xff09;赋值的位置及顺序&#xff08;2&#xff09;举例&#xff08;3&#xff09;字节码文件&#xff08;4&#xff09;进一步探索&#xff08;5&#xff09;最终赋值顺序&#xff08;6&#xff09;实际开发如何选 二、(超纲)关于字节…

梦开始的地方——Adobe Premiere Pro

今天&#xff0c;我们来说说一款老生常谈的相信也是很多人都经常迫切需要的软件。Adobe Premiere Pro&#xff0c;简称Pr&#xff0c;是由Adobe公司开发的一款视频编辑软件。 Premiere Pro是视频编辑爱好者和专业人士必不可少的视频编辑工具。它可以提升您的创作能力和创作自由…

Element中el-table组件右侧空白隐藏-滚动条

开发情况&#xff1a; 固定table高度时&#xff0c;出现滚动条&#xff0c;我们希望隐藏滚动条&#xff0c;或修改滚动条样式&#xff0c;出现table右边出现15px 的固定留白。 代码示例 <el-table class"controlTable" header-row-class-name"controlHead…

httpd(Web服务器)

名词解释 1、URL&#xff1a;Uniform Resource Locator&#xff0c;统⼀资源定位符 2、⽹址格式&#xff1a;<协议>://<主机或主机名>[:port]/<⽬录资源,路径> 3、主机地址/主机名&#xff1a;主机地址是服务器在因特⽹所在的IP地址。主机名就需要域名解析…