【结构型模式】装饰器模式

article/2025/6/7 23:45:29

文章目录

  • 装饰器模式
    • 装饰器模式当中的角色和职责
    • 装饰器模式的代码实现
    • 装饰器模式与代理模式有何不同?
    • 装饰器模式的优缺点
    • 适用场景

装饰器模式

装饰器模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,对于“增加对象功能”而言,装饰器模式比生成子类实现更为灵活,且装饰器模式可以无限叠加。
在这里插入图片描述

装饰器模式当中的角色和职责

装饰器模式的标准类图如下:

画板

  • Component(抽象构件):是具体构件和抽象装饰器的共同父类,声明了在具体构件中需要实现的业务方法。
  • ConcreteComponent(具体构件):是抽象构件的子嘞,用于定义具体的构件对象。装饰器可以为它添加额外的职责(方法)。

装饰器模式的代码实现

参考《Easy 搞定 Golang 设计模式》,下面以“添加手机配件”为场景,实现一个使用装饰器模式的 Demo:

package mainimport "fmt"// --- --- --- 抽象层 --- --- ---
// 定义抽象的构件
type Phone interface {Show() // 构件的功能
}// 装饰器基础类, 本应该定义为 interface, 但由于 Golang 的 interface 只有方法没有成员, 所以定义为 struct
type Decorator struct {phone Phone // 通过组合的方式实现 Decorator 基础类
}func (d *Decorator) Show() {}// --- --- --- 实现层 --- --- ---
// 定义具体的构件
type Apple struct{}func (ap *Apple) Show() {fmt.Println("正在使用苹果手机...")
}type Realme struct{}func (rm *Realme) Show() {fmt.Println("正在使用真我手机...")
}// 定义具体的装饰器
type TiemoDecorator struct {Decorator // 继承基础的装饰器类(主要继承 Phone 的成员属性)
}func (td *TiemoDecorator) Show() {td.phone.Show() // 调用被装饰构件的原方法fmt.Println("贴膜的手机")
}func NewTiemoDecorator(phone Phone) Phone {return &TiemoDecorator{Decorator{phone}}
}type ShoujikeDecorator struct {Decorator
}func (sd *ShoujikeDecorator) Show() {sd.phone.Show()fmt.Println("加装手机壳的手机")
}func NewShoujikeDecorator(phone Phone) Phone {return &ShoujikeDecorator{Decorator{phone}}
}func main() {var iphone Phoneiphone = new(Apple)iphone.Show() // 调用原构件的方法var tiemoIPhone PhonetiemoIPhone = NewTiemoDecorator(iphone)tiemoIPhone.Show()var shoujikeIPhone PhoneshoujikeIPhone = NewShoujikeDecorator(iphone)shoujikeIPhone.Show()var tiemoAndShoujikeIPhone PhonetiemoAndShoujikeIPhone = NewShoujikeDecorator(tiemoIPhone)tiemoAndShoujikeIPhone.Show()
}

装饰器模式与代理模式有何不同?

装饰器模式相较于代理模式而言,其动态性更好一些。可以根据不同的场景选择不同的模式,比如对于逻辑上需要增加的场景,可以使用代理模式;而对于需要无状态平行增加功能的场景,则可以选用装饰器模式,因为装饰器模式可以进行无状态的迭代。

装饰器模式的优缺点

优点

  1. 对于扩展一个对象的功能,装饰器模式比继承更加灵活,不会导致类的个数急剧增加;
  2. 可以通过一种动态的方式来扩展一个对象的功能,从而实现不同的行为;
  3. 可以对一个对象进行多次装饰(无状态地平行添加功能);
  4. 具体的构件类与具体的装饰器类可以独立变化,用户可以根据需要新增具体构件类和具体装饰器类,原有代码无需改变,符合“开闭原则”。

缺点

  1. 使用装饰器模式进行系统设计时会产生很多小的对象,大量小对象的产生势必会占用更多的系统资源,影响程序性能;
  2. 装饰器模式比继承更加灵活,但同时也意味着相较于继承,装饰器模式更容易出错。对于多次装饰的对象,如果出现问题,调试时需要逐级排查,较为繁琐。

适用场景

  1. 通过动态、透明的方式为单个对象添加职责;
  2. 当不能采用继承的方式对系统进行扩展或采用继承不利于系统扩展与维护时,可以使用装饰器模式。

http://www.hkcw.cn/article/gUGOSYAnjW.shtml

相关文章

Ubuntu 挂载新盘

1.磁盘分区 rootljz:/# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 4K 1 loop /snap/bare/5 loop1 7:1 0 104.2M 1 loop /snap/core/17200 loop2 7:2 0 73.9M 1 loop /snap/core22/1908 loop3 7:3 0 104.6M 1 loo…

Flink03-学习-套接字分词流自动写入工具

上一节中通过如下命令启动服务摸来模拟Socket流。 现在我们写一个ServerSocket来模拟让流自动写入不用手动操作。 pom.xml和上一节一致不需要修改 编写代码 同样适用Socket流 // 使用socket流创建一个从 socket 读取文本的数据流,以换行符 \n 作为分隔符DataStre…

2022年 国内税务年鉴PDF电子版Excel

2022年 国内税务年鉴PDF电子版Excelhttps://download.csdn.net/download/2401_84585615/89784658 https://download.csdn.net/download/2401_84585615/89784658 2022年国内税务年鉴是对中国税收政策、税制改革和税务管理实践的全面总结。这份年鉴详细记录了中国税收系统的整体状…

Gitee Wiki:以知识管理赋能 DevSecOps,推动关键领域软件自主演进

关键领域软件研发中的知识管理困境 传统文档管理模式问题显著 关键领域软件研发领域,传统文档管理模式问题显著:文档存储无系统,查找困难,降低效率;更新不及时,与实际脱节,误导开发&#xff1…

Hadoop 3.x 伪分布式 8088端口无法访问问题处理

【Hadoop】YARN ResourceManager 启动后 8088 端口无法访问问题排查与解决(伪分布式启动Hadoop) 在配置和启动 Hadoop YARN 模块时,发现虽然 ResourceManager 正常启动,JPS 进程中也显示无误,但通过浏览器访问 http://主机IP:8088 时却无法打…

【最小生成树】P2573 [SCOI2012] 滑雪

题目 洛谷:P2573 [SCOI2012] 滑雪 分析 题目条件要点分析: 这道题要求 i 能到达 j 的前提是 i 、j 之间有一条连通的边并且i 的高度比 j 高。这意味着本题给出的是一个有向图。时间胶囊可以返回到上一个景点,可以无限使用,意…

2.2.2 06年T2

Stratford的两大对立力量:令人讽刺的居民与令人同情的公司 - 2006年考研英语Text 2精析 本文解析2006年考研英语Text 2,揭示Stratford小镇居民与皇家莎士比亚剧团(RSC)的深层矛盾。 一、原文与翻译 Paragraph 1:对立双方的形成 L1: Stratfor…

基于人工智能算法实现的AI五子棋博弈

1. 项目概述 本项目实现了一个完整的五子棋游戏系统,包含游戏界面、交互逻辑和人工智能对战功能。 系统采用Python语言开发,使用Pygame库进行图形界面渲染,实现了三种游戏模式:人人对战、人机对战和AI对战。 AI算法基于博弈树搜…

在 Ubuntu 系统上使用 Python 的 Matplotlib 库时遇到的字体缺失问题

报错问题 findfont: Font family [SimHei] not found. Falling back to DejaVu Sans. 在现实图片时尝试显示中文字符命令行报错,在图片中显示方框。 最终解决方案 在尝试了各种方法之后,在代码中添加下图中选中行,问题直接解决。

webstrom中git插件勾选提交部分文件时却出现提交全部问题怎么解决

原因是我有个.husky的文件制定了执行提交的时候就是提交所有的文件 修改.husky/pre-commit文件就可以啦 #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh"# 获取通过 WebStorm 提交的暂存文件(仅勾选的部分) STAGED_FILES$(gi…

KINGCMS被入侵

现象会强制跳转到 一个异常网站,请掉截图代码. 代码中包含经过混淆处理的JavaScript,它使用了一种技术来隐藏其真实功能。代码中使用了eval函数来执行动态生成的代码,这是一种常见的技术,恶意脚本经常使用它来隐藏其真实目的。 这段脚本会检…

CMS32M65xx/67xx系列CoreMark跑分测试

CMS32M65xx/67xx系列CoreMark跑分测试 1、参考资料准备 1.1、STM32官方跑分链接 1.2、官网链接 官方移植文档,如下所示,点击红框处-移植文档: A new whitepaper and video explain how to port CoreMark-Pro to bare-metal 1.3、测试软件git下载链接 …

Vue.js教学第十八章:Vue 与后端交互(二):Axios 拦截器与高级应用

Vue 与后端交互(二):Axios 拦截器与高级应用 在上一篇文章中,我们学习了 Axios 的基本用法,包括如何发送不同类型的 HTTP 请求以及基本的配置选项。本文将深入剖析 Axios 的拦截器功能,探讨请求拦截器和响应拦截器的作用、配置方法和应用场景,通过实例展示如何利用拦截…

【信创-k8s】海光/兆芯+银河麒麟V10离线部署k8s1.31.8+kubesphere4.1.3

❝ KubeSphere V4已经开源半年多,而且v4.1.3也已经出来了,修复了众多bug。介于V4优秀的LuBan架构,核心组件非常少,资源占用也显著降低,同时带来众多功能和便利性。我们决定与时俱进,使用1.30版本的Kubernet…

【判断酒酒花数】2022-3-31

缘由对超长正整数的处理&#xff1f; - C语言论坛 - 编程论坛 void 判断酒酒花数(_int64 n) {//缘由https://bbs.bccn.net/thread-508634-1-1.html_int64 t n; int h 0, j 0;//while (j < 3)h t % 10, t / 10, j;//整数的个位十位百位之和是其前缀while (t > 0)h t…

oauth2.0

OAuth 2.0 的工作原理和流程。 OAuth 2.0 是一个授权框架&#xff0c;它允许第三方应用获取对用户资源的有限访问权限&#xff0c;而无需获取用户的密码。以下是详细说明&#xff1a; 1. OAuth 2.0 的四个主要角色 资源所有者&#xff08;Resource Owner&#xff09; 通常是…

笔记本/台式C盘扩容:删除、压缩、跨分区与重分配—「小白教程」

删除C盘右侧分区以扩展 删除分区&#xff0c;也会删除分区中所有资料&#xff0c;请注意备份所有重要资料。 1.WinX选择磁盘管理&#xff0c;右键点击C盘右侧分区&#xff0c;选择删除卷&#xff0c;原分区会变成黑色的“未分配”空间&#xff1b; 2.此时右键C盘选择“扩展卷…

【Bluedroid】蓝牙启动之sdp_init 源码解析

本文围绕Android蓝牙协议栈中 SDP&#xff08;Service Discovery Protocol&#xff0c;服务发现协议&#xff09;模块的初始化函数sdp_init展开&#xff0c;结合核心控制块tSDP_CB及关联数据结构&#xff08;如tL2CAP_CFG_INFO、tCONN_CB等&#xff09;的定义与协作逻辑&#x…

C++学习-入门到精通【13】标准库的容器和迭代器

C学习-入门到精通【13】标准库的容器和迭代器 目录 C学习-入门到精通【13】标准库的容器和迭代器一、标准模板库简介1.容器简介2.STL容器总览3.近容器4.STL容器的通用函数5.首类容器的通用typedef6.对容器元素的要求 二、迭代器简介1.使用istream_iterator输入&#xff0c;使用…

UE5 2D角色PaperZD插件动画状态机学习笔记

UE5 2D角色PaperZD插件动画状态机学习笔记 0.安装PaperZD插件 这是插件下载安装地址 https://www.fab.com/zh-cn/listings/6664e3b5-e376-47aa-a0dd-f7bbbd5b93c0 1.右键创建PaperZD 动画序列 2.添加动画序列 3&#xff0c;右键创建PaperZD AnimBP &#xff08;动画蓝图&am…