装饰器(Decorator)模式Recap

news2025/1/12 6:19:28

设计模式是一套积累并融合了大量经验与成熟思考的设计心法,每一个程序员在成长道路上都应该始终保持对最佳设计方案的不断追求。设计模式也会常用常新,值得反复研究和应用。本文简单Recap一下装饰器(Decorator)模式。

说句体外话,个人认为讲解设计模式最好的书其实是《Head First Design Patterns》一书,因为这本书列举的问题场景和对应的设计模式是高度匹配的,可以让读者深刻体会到对应模式的设计意图,这是所有讲解设计模式的书最重要课题,很多书为了讲解一种模式会“硬凹”出一种需求场景,往往就很“违和”,给读者理解这种模式的设计用意造成了障碍。本文就引用《Head First Design Patterns》一书使用的案例来Recap装饰器(Decorator)模式。

《Head First Design Patterns》一书使用了星巴克咖啡店作为案例,店里售卖不同种类的饮料,每一种饮料都有各自的价格,进而构成如下一个自然的类继承体系:

在这里插入图片描述
由于每一种饮料在制作时都可以根据用户需要添加或调整一些配料或处理方法,比如:使用全脂/脱脂牛奶,添加巧克力成为摩卡风味等等,不同的配方和制作方法价格自然也会不同,都需要重写cost方法,针对这种场景,一种直白的设计思路就是:拓展类型系统,为每一种可能的组合设计一个具体类,预期结果可能如下:

在这里插入图片描述

但是这一设计的“弊病”是很明显的,那就是:“类型爆炸”,众多的类,大部分功能类似或接近,仅仅因为局部的计算逻辑有所差异,就要创建并维护如些多的类是很不合理的。

另一种直白的设计思路就是将这些添加与调整配料或处理方法以属性方式定义到父类Beverage上,由父类Beverage的cost方法统一计算所有这些“附加调味或工序”的费用,然后各饮料子类在自己的cost方法中先计算好自己本身的价格,然后调用父类的cost得到“附加调味或工序”的费用,然后加在一起返回:

在这里插入图片描述
这一方案粗看是没有大问题的,可以应对当前面临的问题,但并不是“最优设计”,在应对未来变化的“弹性”和“兼容性”上是比较脆弱的。举个例子:假设咖啡店未来引入了新的调味或加工工序,例如:燕麦咖啡,榛子咖啡等等,则Beverage类就需要进行相应的修改,不管是属性还cost方法,都要动,此次就能暴露出这一设计方案的“不足之处”了:每次对类族进行拓展时,都要修改现有代码,而不是单纯的添加新代码就可以解决问题,也就是违背的OO设计准则的中“开闭原则”。

此外,延伸一点,在这个设计中,即使不知道或没有意识到“开闭原则”,从最朴素的“OO建模”思想去斟酌一下, 我们也能嗅出一点“Bad Smell”来了,因为像milk,mocha等这些属性根本不应该是Beverage这个基类应该持有的属性,因为不是所有的咖啡都拥有这些属性或特征,美式或意式浓缩咖啡就是例子。其实这个时候,我们这个Beverage类族的OO建模已经开始和现实业务中的实体不符了,这是建模的“失真”,经验告诉我们:只要对象建模与实际业务实体之间存在不恰当的映射关系,或早或晚都会出现让人感到“别扭”的地方,表现可能是:总是需要频繁的修改代码,或修改一处代码会牵连更多的代码同步修改和测试等等。

接下来,就是最优设计:装饰器(Decorator)模式的解决方案了:
请添加图片描述
整体设计思路一目了然:把那些“附加调味或工序”抽离到独立的子类体系中,这串子类统称为“CondimentDecorator”,这些类本身继承自Beverage,也就是说,它们性质上,也是一种独立的Beverage,但其构造函数必须以一个现成的Beverage的具体类作为参数,那就意味着它们不能独立初始化,而必须要以一个基础Beverage实例(如Espresso)作为包裹对象,在叠加自己的计费逻辑进去。

这一改动,最大的收益就是彻底规避了后续拓展时改动现有代码的风险,当有新燕麦或榛子咖啡上线时,只须在CondimentDecorator下添加相应的子类并实现先关逻辑即可,是对开闭原则非常完美的一次诠释。

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

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

相关文章

【Paper】2020_离散多智能体系统的事件触发二分一致性研究_刘雨欣

文章目录第 4 章 有向符号图下离散多智能体系统的事件触发二分一致性4.3.1 示例一4.3.2 示例二系统 动态方程、控制输入及事件触发条件分别如式(2.1)、(3.1)及式(3.6)所示。 本文考虑一阶离散多智能体系统,第 iii 个智能体的动态方程如下: xi(k1)xi(k)ui(k)(2.1)\b…

千字长文!C++每日一练——Day3

🐑本文作者:C橙羊🐑 🎮🔊本文代码适合编译环境:DEV-C💻 ✨🧨温馨提示:此文乃作者心血,如要转载请标注版权,否则视为抄袭!&#x1f389…

多线程——线程同步器CountDownLatch

多线程——线程同步器CountDownLatch(一)CountDownLatch案例入门【1】CountDownLatch和join的区别【2】CountDownLatch案例一:等待线程等待工作线程【3】CountDownLatch案例二:主线程main等待子线程【4】CountDownLatch案例三&…

.NET Conf China 2022 精彩回顾 | IOT专场

12月充满惊喜 各种美好的节日纷至沓来 奖励一年辛苦劳作的我们 本月程序员第一场节日 就是精彩的 .NET Conf China 2022 .NET Conf China 2022是面向开发人员的社区峰会,延续 .NET Conf 2022的活动,庆祝 .NET7的发布和回顾过去一年来 .NET在中国的发…

举个栗子~Alteryx 技巧(4):教你设置 Alteryx Server 用户权限

分析用户在用 Alteryx Designer 创建好工作流之后,如何在企业内部实现共享和管理分析工作流程、模型及数据呢?方法很简单:发布到 Alteryx Server ! Alteryx Server 通过内置的数据治理、集中管理的安全性和高可用性,可…

svn:E720005 move .svn/tmp拒绝访问

cleanup也clean不了 此时要用sqlite3.exe来解决了到有.svn的目录地下,把sqllite3.exe拷贝到这个下面 在目录里面打开cmd窗口,执行 sqlite3 .svn/wc.db "select * from work_queue" 如果查出内容,那么执行 sqlite3 .svn/wc.db …

【Dubbo3高级特性】「性能优化技术」Dubbo3完成扩展使用高效的Kryo和FST序列化开发实战

系列文章目录 如果你看到了这里,那么接下来你将会认识Dubbo3的诞生将如何引领微服务领域更进一步,从而迈入云原生的领域,这当然不仅仅是Dubbo3,之前也介绍了Java生态另外一个云原生领域的技术Quarkus等技术,而本文内容…

Spring Boot 实现微信点餐系统

架构 前后端分离: 部署架构: 补充: setting.xml 文件的作用:settings.xml是maven的全局配置文件。而pom.xml文件是所在项目的局部配置。Settings.xml中包含类似本地仓储位置、修改远程仓储服务器、认证信息等配置。 maven的作用…

校招求职经验分享——我是如何本科进入大厂的

写在开头 最近签完了三方,大学前三年的生涯规划和努力最终还是得到了兑现,脑子里不断涌现这几年来的经历,一直想着写点什么东西记录一下,刚好大四空闲时间真的太多,心血来潮,不如还是写写吧,记录…

mysql cdc 整库迁移 (mysql to mysql)

技术思想 利用 mysql catalog,mysql cdc,flink jdbc 等技术实现 mysql 整库迁移至下游数据库,这里是示范 mysql to mysql ,其他 sink 组件可自行扩展实现。 通过 flink ParameterTool,可以选择是整库同步还是多表亦或…

2023年天津天狮学院专升本报名考试的安排

天津天狮学院2023年高职升本科考试报名时间安排的通知 一、报名条件 报名条件和具体要求按照天津市招生委员会的文件规定执行。考生必须完成文化课报名环节,且填报天津天狮学院志愿,且具备我校提出的线上考试条件,方可报考我校专业课考试。考…

Java作业

这里写自定义目录标题java16次作业新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是…

python-网络编程

python-网络编程 网络编程的理论概述: 现在的生活离不开网络,例如手机,电脑,平板,都是网络的代名词,通过一些APP,浏览器,获取大量的信息如 文字、声音、视频,这都是从网…

[Linux]------线程同步和信号量

文章目录前言一、条件变量同步概念与竞态条件条件变量函数初始化销毁等待条件满足唤醒等待为什么pthread_cond_wait需要互斥量?条件变量使用规范二、生产者消费者模型为何要使用生产者消费者模型生产者消费者模型的优点基于BlockingQueue的生产者消费者模型C queue模…

1.MyBatis简介

1.概念 MyBatis是一款开源的持久层框架,它支持定制化SQL、存储过程以及高级映射。 与其它ORM框架不同,MyBatis没有将Java对象与数据表关联起来,而是作为Java方法和SQL语句的桥梁,一般称它为“半自动化ORM”框架。 2.Mybatis架构 …

【软件测试】在我刚上岗时,资深测试给我的建议让我受益匪浅......

目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 建立测试基线 当我还…

BNB Chain对Zebec生态大力扶持,ZBC或继续登录一线平台

在行业早期开始,流支付赛道就已经具备了早期的轮廓,而在流支付协议Zebec Protocol出现后,该领域被推向了一个新的发展高度,并得到加密领域以及传统商业领域的高度关注。而随着生态的商业进展不断推进、生态不断壮大,Ze…

C++代码优化(1):条款1~4

"不要烟火不要星光,只要问问你内心的想法。" 本栏仅仅 由对《Effictive C》其中的一系列条款,掺杂着自己一些愚钝的理解而写的。 ---前言 条款01: 尽量以const、enum、inline 替换 #define 在谈及上述好几个关键字 与define宏定义的关系&…

Intel i226芯片4端口千兆以太网卡 2.5GPoE工业相机图像采集卡介绍

PCIe-8634图像采集卡是一款基于 Intel i226芯片高性能千兆工业级 PCIe*4 POE网卡,具有传输速度高、兼容性强、性能稳定的特点,可广泛主要应用于网络高清监控、无线覆盖、工业自动化等领域。 RJ45千兆网络采用4 k Intel226千兆网络芯片,支持10/100/1000/2500Mbps传输…

microservices 简介

油鹳视频 Microservices explained - the What, Why and How? https://www.youtube.com/watch?vrv4LlmLmVWk&t2s microservices 是一种软件体系结构, microservices architecture(微服务架构) 是与传统的 monolithic architecture(整体式架构,一体…