Java设计模式实战:装饰模式在星巴克咖啡系统中的应用

一、装饰模式简介

       装饰模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

二、星巴克咖啡系统设计

根据提供的UML类图,我们来设计一个星巴克咖啡下单系统,该系统可以计算不同咖啡和调料组合的价格。

系统组成

  1. 抽象组件(Beverage):相当于Component类,是所有咖啡和调料的基类

  2. 具体组件:HouseBlend、Expresso、DarkRoast、Decaf,代表不同类型的咖啡

  3. 装饰器(CondimentDecorator):抽象装饰类

  4. 具体装饰器:Milk、Mocha、Soy、Whip,代表不同的调料

三、代码实现

1. 抽象组件(Beverage)

/*** 抽象组件 - 饮料基类* 相当于装饰模式中的Component角色*/
public abstract class Beverage {// 饮料描述,初始为"Unknown Beverage"String description = "Unknown Beverage";/*** 获取饮料描述* @return 饮料描述字符串*/public String getDescription() {return description;}/*** 计算饮料价格 - 抽象方法,由子类实现* @return 饮料价格*/public abstract double cost();
}

2. 具体组件(各种咖啡类型)

2.1 HouseBlend 咖啡

/*** 具体组件 - 混合咖啡*/
public class HouseBlend extends Beverage {public HouseBlend() {description = "House Blend Coffee";}@Overridepublic double cost() {return 0.89;  // 基础价格0.89美元}
}

2.2 Expresso 咖啡

/*** 具体组件 - 浓缩咖啡*/
public class Expresso extends Beverage {public Expresso() {description = "Expresso";}@Overridepublic double cost() {return 1.99;  // 基础价格1.99美元}
}

2.3 DarkRoast 咖啡

/*** 具体组件 - 深焙咖啡*/
public class DarkRoast extends Beverage {public DarkRoast() {description = "Dark Roast Coffee";}@Overridepublic double cost() {return 0.99;  // 基础价格0.99美元}
}

2.4 Decaf 咖啡

/*** 具体组件 - 低因咖啡*/
public class Decaf extends Beverage {public Decaf() {description = "Decaf Coffee";}@Overridepublic double cost() {return 1.05;  // 基础价格1.05美元}
}

3. 抽象装饰器(CondimentDecorator)

/*** 抽象装饰器 - 调料装饰器基类* 继承自Beverage,所以装饰器可以嵌套装饰器*/
public abstract class CondimentDecorator extends Beverage {/*** 获取完整描述 - 抽象方法* 每个具体装饰器需要实现如何添加自己的描述*/@Overridepublic abstract String getDescription();
}

4. 具体装饰器(各种调料)

4.1 Milk 牛奶

/*** 具体装饰器 - 牛奶*/
public class Milk extends CondimentDecorator {// 被装饰的饮料Beverage beverage;public Milk(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Milk";  // 添加牛奶描述}@Overridepublic double cost() {return beverage.cost() + 0.10;  // 增加0.10美元}
}

4.2 Mocha 摩卡

/*** 具体装饰器 - 摩卡*/
public class Mocha extends CondimentDecorator {Beverage beverage;public Mocha(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Mocha";  // 添加摩卡描述}@Overridepublic double cost() {return beverage.cost() + 0.20;  // 增加0.20美元}
}

4.3 Soy 豆浆

/*** 具体装饰器 - 豆浆*/
public class Soy extends CondimentDecorator {Beverage beverage;public Soy(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Soy";  // 添加豆浆描述}@Overridepublic double cost() {return beverage.cost() + 0.15;  // 增加0.15美元}
}

4.4 Whip 奶泡

/*** 具体装饰器 - 奶泡*/
public class Whip extends CondimentDecorator {Beverage beverage;public Whip(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Whip";  // 添加奶泡描述}@Overridepublic double cost() {return beverage.cost() + 0.10;  // 增加0.10美元}
}

5. 客户端使用示例

/*** 星巴克咖啡店 - 客户端代码*/
public class StarbuzzCoffee {public static void main(String args[]) {// 示例1:一杯纯EspressoBeverage beverage1 = new Expresso();System.out.println(beverage1.getDescription() + " $" + beverage1.cost());// 示例2:DarkRoast加双份Mocha和WhipBeverage beverage2 = new DarkRoast();beverage2 = new Mocha(beverage2);  // 第一次装饰:加Mochabeverage2 = new Mocha(beverage2);  // 第二次装饰:再加Mochabeverage2 = new Whip(beverage2);   // 第三次装饰:加WhipSystem.out.println(beverage2.getDescription() + " $" + beverage2.cost());// 示例3:HouseBlend加Soy、Mocha和WhipBeverage beverage3 = new HouseBlend();beverage3 = new Soy(beverage3);   // 第一次装饰:加Soybeverage3 = new Mocha(beverage3);  // 第二次装饰:加Mochabeverage3 = new Whip(beverage3);   // 第三次装饰:加WhipSystem.out.println(beverage3.getDescription() + " $" + beverage3.cost());}
}

四、代码结构说明

  1. Beverage 是所有饮料的基类,定义了基本接口

  2. 具体咖啡类型(HouseBlend、Expresso等)继承Beverage,实现具体价格

  3. CondimentDecorator是装饰器基类,也继承自Beverage

  4. 具体调料(Milk、Mocha等)继承CondimentDecorator,包装一个Beverage对象

  5. 客户端可以自由组合咖啡和调料,通过层层装饰实现复杂组合

五、装饰模式的优势

  1. 灵活性:可以动态地添加或删除功能,比继承更灵活

  2. 避免类爆炸:不需要为每种组合创建子类

  3. 符合开闭原则:对扩展开放,对修改关闭

  4. 运行时添加功能:可以在运行时决定添加哪些装饰

六、总结

       通过这个星巴克咖啡系统的例子,我们看到了装饰模式在实际应用中的强大之处。它让我们能够轻松地组合各种咖啡和调料,而不需要创建大量的子类。这种模式特别适合那些需要动态、透明地添加对象功能的场景。

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

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

相关文章

使用MPI-IO并行读写HDF5文件

使用MPI-IO并行读写HDF5文件 HDF5支持通过MPI-IO进行并行读写,这对于大规模科学计算应用非常重要。下面我将提供C和Fortran的示例程序,展示如何使用MPI-IO并行读写HDF5文件。 准备工作 在使用MPI-IO的HDF5之前,需要确保: HDF5库编译时启用…

七、自动化概念篇

自动化测试概念 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常,在设计了测试用例并通过评审之后,由测试人员根据测试用例中描述的过程一步步执行测试,得到实际结果与期望结果的比较。在此过程中,为了节省人…

redis cluster 的通信机制

Redis Cluster 的通信机制是其分布式架构的核心,基于 Gossip 协议 和 Cluster Bus 实现节点间状态同步与数据协调。以下是其通信机制的核心要点: 二进制协议:数据以字节流形式编码(如Protobuf、Thrift、MQTT、Gossip)。…

CTF web入门之文件上传

知识点 产生文件上传漏洞的原因 原因: 对于上传文件的后缀名(扩展名)没有做较为严格的限制 对于上传文件的MIMETYPE(用于描述文件的类型的一种表述方法) 没有做检查 权限上没有对于上传的文件目录设置不可执行权限,(尤其是对于shebang类型的文件) 对于web server对于上传…

PhotoShop学习09

1.弯曲钢笔工具 PhotoShop提供了弯曲钢笔工具可以直观地创建路径,只需要对分段推拉就能够进行修改。弯曲港币工具位于工具面板中的钢笔工具里,它的快捷键为P。 在使用前,可以把填充和描边选为空颜色,并打开路径选项,勾…

tsconfig.json配置不生效

说明一下我遇到的问题,这是我的配置文件代码的 {"compilerOptions": {"module": "none","target": "ES5","outFile": "./dist/bundle.js"} } 和我想象不同的是,我编译成 js 没…

源代码加密之零日攻击

# SDC沙盒:有效防御零日攻击的多层防护体系 在当今复杂多变的网络安全环境中,零日攻击已成为企业面临的重大威胁之一。零日攻击利用尚未被公众发现或尚未被软件供应商修复的漏洞进行攻击,具有极高的隐蔽性和破坏性。SDC沙盒作为一种先进的数…

记录一次TDSQL网关夯住故障

环境信息: TDSQL-MySQL同城双中心集群,集中式实例,一主三副本,每个中心两个db副本,每个中心一个VIP,V每个IP通过硬件做负载均衡指向该中心两个proxy,操作系统为麒麟v10 arm。 故障描述&#xf…

代码随想录八股训练营完结总结

! 40天的训练营,我总结了自己完整的八股文,后续在面试过程中可以补充 很感谢这次训练营,真的高频,在面试中能击中60%以上,剩下的就靠平时的积累了。 感谢训练营的小伙伴,很多次想偷懒&#x…

VS Code 的 .S 汇编文件里面的注释不显示绿色

1. 确认文件语言模式 打开 .S 文件后,查看 VS Code 右下角的状态栏,确认当前文件的识别模式(如 Assembly、Plain Text 等)。如果显示为 Plain Text 或其他非汇编模式: 点击状态栏中的语言模式(如 Plain Te…

iphone各个机型尺寸

以下是苹果(Apple)历代 iPhone 机型 的屏幕尺寸、分辨率及其他关键参数汇总(截至 2023年10月,数据基于官方发布信息): 一、标准屏 iPhone(非Pro系列) 机型屏幕尺寸(英寸…

VSCode写java时常用的快捷键

首先得先安好java插件 1、获取返回值 这里是和idea一样的快捷键的,都是xxxx.var 比如现在我new一个对象 就输入 new MbDo().var // 点击回车即可变成下面的// MbDo mbDo new MbDo()//以此类推get方法也可获取 mbDo.getMc().var // 点击回车即可变成下面的 // St…

相机内外参

文章目录 相机内参相机外参 相机的内外参是相机标定过程中确定的重要参数,用于建立图像像素坐标与实际世界坐标之间的关系。 相机内参 定义:相机内参是描述相机内部光学和几何特性的参数,主要包括焦距、主点坐标、像素尺度因子以及畸变系数等…

【视频目标分割论文集】Efficient Track Anything0000

github 摘要 视频对象分割和追踪任意目标领域出现了强大的工具——分割任意模型 2(SAM 2)。SAM 2 实现令人印象深刻的视频对象分割性能的关键组成部分包括用于帧特征提取的大型多阶段图像编码器,以及存储过去帧记忆上下文以辅助当前帧分割的…

CSS学习02 动态列数表格开发,解决多组数据布局与边框重合问题

概要 在前端开发中,表格常用于展示结构化数据。当数据组的字段数量不统一时(如有的行包含 3 组数据,有的行包含 2 组或 1 组),传统固定列数的表格会出现结构错位、边框重合等问题。本文通过 HTML/CSS 规范方法&#x…

Spark-core编程总结

1.reduce‌ 功能‌:聚集RDD中的所有元素,先聚合分区内数据,再聚合分区间数据。 示例‌:rdd.reduce(__) 将RDD中的所有整数相加。 2.collect‌ 功能‌:在驱动程序中,以数组Array的形式返回数据集的所有元…

处理Long类型长度超长导致前端精度丢失问题

1,问题场景 后端返回的Long类型的数据,超10000000000000000,前端处理的时候,数据被截断了。比如tchId: 11073477511443988481, 前端根据tchId获取下一环节信息的时候,传的tchId变成了11073477511443988400&…

ONVIF/RTSP/RTMP协议EasyCVR视频汇聚平台RTMP协议配置全攻略 | 直播推流实战教程

在现代化的视频管理和应急指挥系统中,RTMP协议作为一种高效的视频流传输方式,正变得越来越重要。无论是安防监控、应急指挥,还是物联网视频融合,掌握RTMP协议的接入和配置方法,都是提升系统性能和效率的关键一步。 今天…

安徽京准:GPS北斗卫星时空信号安全防护装置(授时)介绍

安徽京准:GPS北斗卫星时空信号安全防护装置(授时)介绍 1、主要特点 ★信号加固功能: GPS/BDS单系统信号拒止情况下(包含受到GPS L1欺骗干扰、GPS L1压制干扰、BDS B1欺骗干扰、BDS B1压制干扰)&#xff…

探索原生JS的力量:自定义实现类似于React的useState功能

1.写在前面 本方案特别适合希望在历史遗留的原生JavaScript项目中实现简单轻量级数据驱动机制的开发者。无需引入任何框架或第三方库,即可按照此方法封装出类似于React中useState的功能,轻松为项目添加状态管理能力,既保持了项目的轻量性&am…