当前位置: 首页 > news >正文

设计模式大白话之装饰者模式

想象一下,你走进一家咖啡馆,点了一杯美式咖啡。但是,你可能还想根据自己的口味添加一些东西,比如奶泡、巧克力粉、焦糖酱或是肉桂粉。每次你添加一种配料,你的咖啡就会变得更丰富,同时价格也会相应增加。

在软件设计中,装饰者模式就是让你能够在不改变原始对象的情况下,动态地给它添加新功能或增强现有功能。这就好比你在咖啡上加配料,不是通过制作一种全新的咖啡,而是通过在现有的基础上增加东西。

比如,假设你正在开发一个文本编辑器,你希望用户可以选择开启一些额外的功能,比如语法高亮、行号显示、自动完成等。你不想为每一种可能的组合都创建一个单独的文本编辑器类,因为那样会有无数种组合,维护起来会非常困难。

这时,装饰者模式就派上用场了。你可以创建一个基本的文本编辑器类,然后为每一个额外功能创建一个装饰者类。当用户选择开启某项功能时,你就在基本的文本编辑器上“装饰”上相应的装饰者。这样,用户就可以根据自己的需求,动态地定制他们自己的文本编辑器,而不需要重新编写整个程序。

简而言之,装饰者模式就像是给你的软件产品添加“配料”,让它变得更有个性,更符合用户的需求,而无需更改其核心结构。

 以一家奶茶店为例,使用装饰者模式来动态地给奶茶添加各种配料。我们将创建一个基础的奶茶类,然后使用装饰者类来添加不同的配料,如珍珠、布丁、红豆、仙草、芝士等。

首先,我们定义奶茶的基本接口:
public abstract class Drink {// 基本属性protected String description = "Unknown Drink";// 获取描述public String getDescription() {return description;}// 设置描述public void setDescription(String description) {this.description = description;}// 抽象方法,计算价格public abstract double cost();
}
接下来,我们创建基础的奶茶类:
public class MilkTea extends Drink {public MilkTea() {description = "Milk Tea";}public double cost() {return 3.5; // 假设一杯基础奶茶的价格是3.5元}
}
然后,我们定义装饰者基类:
public abstract class AddOns extends Drink {protected Drink drink;public AddOns(Drink drink) {this.drink = drink;}public String getDescription() {return drink.getDescription();}public double cost() {return drink.cost();}
}
接着,我们创建具体的配料装饰者:
public class Boba extends AddOns {public Boba(Drink drink) {super(drink);}@Overridepublic String getDescription() {// 返回被装饰对象的描述return super.getDescription()+",  with Boba";}@Overridepublic double cost() {return drink.cost() + 1.0; // 添加珍珠的成本}
}
public class Pudding extends AddOns {public Pudding(Drink drink) {super(drink);}@Overridepublic String getDescription() {// 返回被装饰对象的描述return super.getDescription()+", with Pudding";}@Overridepublic double cost() {return drink.cost() + 0.8; // 添加布丁的成本}
}
public class RedBeans extends AddOns {public RedBeans(Drink drink) {super(drink);}@Overridepublic String getDescription() {// 返回被装饰对象的描述return super.getDescription()+",  with Red Beans";}@Overridepublic double cost() {return drink.cost() + 0.7; // 添加红豆的成本}
}
最后,在主函数中使用这些装饰者:
public class Main {public static void main(String[] args) {Drink milkTea = new MilkTea();System.out.println(milkTea.getDescription() + ": " + milkTea.cost());Drink milkTeaWithBoba = new Boba(milkTea);System.out.println(milkTeaWithBoba.getDescription() + ": " +  milkTeaWithBoba.cost());Drink milkTeaWithBobaAndPudding = new Pudding(milkTeaWithBoba);System.out.println(milkTeaWithBobaAndPudding.getDescription() + ": " + milkTeaWithBobaAndPudding.cost());Drink milkTeaWithBobaAndRedBeans = new RedBeans(milkTeaWithBoba);System.out.println(milkTeaWithBobaAndRedBeans.getDescription() + ": " + milkTeaWithBobaAndRedBeans.cost());}
}
执行结果
Milk Tea: 3.5
Milk Tea,  with Boba: 4.5
Milk Tea,  with Boba, with Pudding: 5.3
Milk Tea,  with Boba,  with Red Beans: 5.2

在上述代码中,Drink 是奶茶及其配料的抽象基类,MilkTea 是基本的奶茶实现,AddOns 是所有配料的基类,而Boba, Pudding, RedBeans 分别是具体的配料装饰者。通过组合不同的装饰者,我们可以轻松地构建出各种不同配料组合的奶茶,而且这些组合是在运行时动态决定的。

理解这种思想然后之后就是如何熟练运用,在有需要的时候。

相关文章:

设计模式大白话之装饰者模式

想象一下,你走进一家咖啡馆,点了一杯美式咖啡。但是,你可能还想根据自己的口味添加一些东西,比如奶泡、巧克力粉、焦糖酱或是肉桂粉。每次你添加一种配料,你的咖啡就会变得更丰富,同时价格也会相应增加。 在…...

动手学深度学习6.3 填充和步幅-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。 本节课程地址:填充和步幅_哔哩哔哩_bilibili 代码实现_哔哩哔哩_bilibili 本节教材地址:6.3. 填充和…...

函数的形状怎么定义?

在TypeScript中,函数的形状可以通过多种方式定义,以下是几种主要的方法: 1、函数声明:使用function关键字声明函数,并直接在函数名后的括号内定义参数,通过冒号(:)指定参数的类型&a…...

Windows 虚拟机服务器项目部署

目录 一、部署JDK下载JDK安装JDK1.双击 jdk.exe 安装程序2.点击【下一步】3.默认安装位置,点击【下一步】4.等待提取安装程序5.默认安装位置,点击【下一步】6.等待安装7.安装成功,点击【关闭】 二、部署TomcatTomcat主要特点包括:…...

JDBC(2)基础篇2——增删改查及常见问题

目录 一、基于PreparedStatement实现CRUD 1.查询单行单列 2.查询单行多列 3.查询多行多列 4.新增 5.修改 6.删除 7.总结 二、常见问题 1.资源的管理 2.SQL语句问题 3.SQL语句未设置参数问题 4.用户名或密码错误问题 5.通信异常 总结 一、基于PreparedStatement实…...

JVM知识点梳理

目录标题 1.类加载机制1.1 Java 运行时一个类是什么时候被加载的?1.2 JVM 一个类的加载过程?1.3 一个类被初始化的过程?1.4 继承时父子类的初始化顺序是怎样的?1.5 究竟什么是类加载器?1.6 JVM 有哪些类加载器?1.7 JVM 中不同的类加载器加载哪些文件?1.8 JVM 三层类加载…...

产品经理-一份标准需求文档的8个模块(14)

一份标准优秀的产品需求文档包括: ❑ 封面; ❑ 文档修订记录表; ❑ 目录; ❑ 引言; ❑ 产品概述:产品结构图 ❑ 详细需求说明:产品逻辑图、功能与特性简述列表、交互/视觉设计、需求详细描述&am…...

如何用一个例子向10岁小孩解释高并发实时服务的单线程事件循环架构

I/O密集型进程和CPU密集型进程 聊天应用程序、MMO(大型多人在线)游戏、金融交易系统、等实时服务需要处理大量并发流量和实时数据。 这些服务是I/O密集型的,因为它们花费大量资源处理输入输出操作,例如高吞吐量、低延迟网络通信…...

如何为帕金森病患者选择合适的步行辅助设备?

选择步行辅助设备的步骤和建议 为帕金森病患者选择合适的步行辅助设备时,应考虑以下几个关键因素: 患者的具体症状和需求:帕金森病患者的步行困难可能包括冻结步态、平衡能力下降和肌肉僵硬。选择设备时,应考虑这些症状&#xff…...

【排序算法】1.冒泡排序-C语言实现

冒泡排序(Bubble Sort)是最简单和最通用的排序方法,其基本思想是:在待排序的一组数中,将相邻的两个数进行比较,若前面的数比后面的数大就交换两数,否则不交换;如此下去,直…...

Unity最新第三方开源插件《Stateful Component》管理中大型项目MonoBehaviour各种序列化字段 ,的高级解决方案

上文提到了UIState, ObjectRefactor等,还提到了远古的NGUI, KBEngine-UI等 这个算是比较新的解决方法吧,但是抽象出来,问题还是这些个问题 所以你就说做游戏是不是先要解决这些问题? 而不是高大上的UiImage,DoozyUI等 Mono管理引用基本用法 ① 添加Stateful Component …...

Spark SQL----INSERT TABLE

Spark SQL----INSERT TABLE 一、描述二、语法三、参数四、例子4.1 Insert Into4.2 Insert Overwrite 一、描述 INSERT语句将新行插入表中或覆盖表中的现有数据。插入的行可以由值表达式指定,也可以由查询结果指定。 二、语法 INSERT [ INTO | OVERWRITE ] [ TABL…...

socket功能定义和一般模型

1. socket的功能定义 socket是为了使两个应用程序间进行数据交换而存在的一种技术,不仅可以使同一个主机上两个应用程序间可以交换数据,而且可以使网络上的不同主机间上的应用程序间进行通信。 2. 图解socket的服务端/客户端模型...

如何在linux中给vim编辑器添加插件

在Linux系统中给Vim编辑器添加插件通常通过插件管理器来完成,以下是一般的步骤: 1.使用插件管理器安装插件 安装插件管理器(如果尚未安装): 常见的插件管理器包括 Vundle、vim-plug 和 Pathogen 等。你可以根据个人喜…...

Web 中POST为什么会发送两次请求

文章目录 前言一、浏览器的重试机制二、跨域请求与预检请求三、表单的自动提交四、服务器配置问题五、前端代码的重复执行六、同源策略与CORS总结 前言 我们在做Web开发时,经常会使用浏览器F12查看请求参数是否正确,但是会发现POST请求,一个地…...

C语言经典程序100案例

C语言经典程序100题(完整版) 【程序1】题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数都是多少 程序分析:可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去掉不满足条件的排列。 #include "stdio…...

南京邮电大学统计学课程实验3 用EXCEL进行方差分析 指导

一、实验描述 实验目的 1、学会在计算机上利用EXCEL进行单因素方差分析; 2、学会在计算机上利用EXCEL进行无重复的双因素方差分析。 二、实验环境 实验中使用以下软件和硬件设备 (1)Windows XP操作系统; (2&am…...

2024-07-13 Unity AI状态机2 —— 项目介绍

文章目录 1 项目介绍2 模块介绍2.1 BaseState2.2 ...State2.2.1 PatrolState2.2.2 ChaseState / AttackState / BackState 2.3 StateMachine2.4 Monster 3 其他功能4 类图 项目借鉴 B 站唐老狮 2023年直播内容。 点击前往唐老狮 B 站主页。 1 项目介绍 ​ 本项目使用 Unity 2…...

shell脚本-linux如何在脚本中远程到一台linux机器并执行命令

需求:我们需要从11.0.1.17远程到11.0.1.16上执行命令 实现: 1.让11.0.1.17 可以免密登录到11.0.1.16 [rootlocalhost ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created d…...

Spring Data Redis + Redis数据缓存学习笔记

文章目录 1 Redis 入门1.1 简介1.2 Redis服务启动与停止(Windows)1.2.1 服务启动命令1.2.2 客户端连接命令1.2.3 修改Redis配置文件1.2.4 Redis客户端图形工具 2. Redis数据类型2.1 五种常用数据类型介绍 3. Redis常用命令3.1 字符串操作命令3.2 哈希操作…...

讯飞星辰 Coding Plan 邀请码

邀请码:MAAS-CE9B96C2可点击链接 前往页面:https://maas.xfyun.cn/packageSubscription?inviteCodeMAAS-CE9B96C2(优惠:使用邀请码购买 Coding Plan,可获得支付金额等额礼品卡,可用于平台模型调用抵扣&…...

宇视云团队模式访客预约操作流程

宇视云团队模式访客预约操作流程 本文将从创建访客邀请、来访信息登记、线上审批操作到最终多种方式通行,为您提供一步步的详细图文说明,引导企业内部员工和外部来访人员轻松上手,让访客接待更高效、更安全。 第一步:受访者创建“…...

Python运算符:比较运算符(等于不等等于大于小于)与返回值

Python运算符:比较运算符(等于不等等于大于小于)与返回值📚 本章学习目标:深入理解比较运算符(等于不等等于大于小于)与返回值的核心概念与实践方法,掌握关键技术要点,了…...

JMeter gRPC性能测试解决方案:微服务协议性能验证技术实现

JMeter gRPC性能测试解决方案:微服务协议性能验证技术实现 【免费下载链接】jmeter-grpc-request JMeter gRPC Request load test plugin for gRPC 项目地址: https://gitcode.com/gh_mirrors/jm/jmeter-grpc-request 随着微服务架构的普及,gRPC已…...

MySQL系统架构

一、MySQL架构核心层连接层:连接器、认证授权、连接池/线程管理服务层:解析器、优化器、执行器(决定 SQL 怎么执行)存储引擎层:InnoDB/MyISAM 等,负责数据存取(常用 InnoDB)事务与并…...

Data Connection (数据连接) 架构设计

description: “移动数据连接 (Data Connection) 与 PDN 会话架构设计,深入剖析 DataNetwork 状态机、数据可用性评估引擎、重试退避算法、以及跨 APN 的并发管理策略。” 当手机完成网络注册(ServiceStateTracker 确定已注册到运营商网络)后,用户最关心的一件事就是:能不…...

蓝牙5.0广播包PDU字段逐行解读:从ADV_IND到AUX_CHAIN_IND,新手也能看懂的报文拆解

蓝牙5.0广播包PDU字段逐行解读:从ADV_IND到AUX_CHAIN_IND 在物联网设备开发中,蓝牙低功耗(BLE)技术因其低功耗和简单连接特性而广受欢迎。但对于刚接触BLE协议的开发者来说,最头疼的莫过于理解那些晦涩的协议文档和复…...

110页PPT的大数据产品设计和应用,含整体方案和多个行业案例,满分PPT

📘【文档介绍】🌐《大数据应用型产品设计方法及行业案例介绍》PPT共110页可编辑文档,它将是你招投标、行业解决方案的重要参考资料。 🔑【掌握大数据,引领企业未来】 作为企业管理者,需要的不仅是管理智慧&…...

PowerSetting下载慢?CDN加速+离线包分发方案

运维团队最怕什么?不是流量高峰,而是高峰期偏偏遇到软件包下载失败、更新卡死、内网带宽被打满。PowerSetting这类工具包虽然不大,但在大规模批量部署时,每一次从公网拉取都是一次不确定的赌博,网络抖动、节点失效、外…...

Python操控AB PLC避坑指南:pylogix读写数组、字符串和UDT的实战细节

Python操控AB PLC避坑指南:pylogix读写数组、字符串和UDT的实战细节 当工业自动化遇上Python,pylogix库成为了连接AB PLC与Python世界的桥梁。但在处理数组、字符串和用户自定义数据类型(UDT)时,即便是经验丰富的开发…...