设计模式——装饰者模式

设计模式——装饰者模式

  • 1.问题
    • 1.1 方案一
    • 1.2 方案二
  • 2.装饰者模式
    • 2.1 基本介绍
    • 2.2 结构
    • 2.3 代码实现
  • 3.小结

1.问题

咖啡订单项目:

  1. 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
  2. 调料:Milk、Soy(豆浆)、Chocolate
  3. 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
  4. 使用 OO 的来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以单品咖啡+调料组合。

1.1 方案一

方案一
问题解析:

  1. Drink 是一个抽象类,表示饮料
  2. des 就是对咖啡的描述,比如咖啡的名字
  3. cost()方法就是计算费用,Drink 类中做成一个抽象方法
  4. Decaf 就是单品咖啡, 继承 Drink,并实现 cost
  5. Espress && Milk 就是单品咖啡+调料,这个组合很多,容易产生过多的子类

1.2 方案二

方案二
这里的milk、soy、chocolate都是Boolean类型

问题解析:

  1. 方案2可以控制类的数量,不至于造成很多的类在增加或者删除调料种类时,代码的维护量很大
  2. 考虑到用户可以添加多份 调料时,可以将 hasMilk 返回一个对应 int
  3. 考虑使用 装饰者 模式

2.装饰者模式

2.1 基本介绍

  1. 装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)
  2. 这里提到的动态的将新功能附加到对象和 ocp 原则

2.2 结构

装饰(Decorator)模式中的角色:

  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子
    类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附
    加的责任。

2.3 代码实现

类图展示:
核心
抽象类Drink:

public abstract class Drink {private String description;private double price;public abstract double cost();public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}
}

装饰者:

public class Decorator extends Drink {private Drink drink;public Decorator(Drink drink) {this.drink = drink;}@Overridepublic double cost() {return super.getPrice() + drink.cost();}@Overridepublic String getDescription() {return super.getDescription() + " " + getPrice() + " && " + drink.getDescription();}
}

Coffee:

public class Coffee extends Drink {@Overridepublic double cost() {return super.getPrice();}
}

Coffee子类:

public class Decaf extends Coffee {public Decaf() {setDescription("无因咖啡");setPrice(1);}
}
public class Espresso extends Coffee {public Espresso() {setDescription("意大利咖啡");setPrice(6);}
}
public class LongBlack extends Coffee {public LongBlack() {setDescription("longBlack");setPrice(5);}
}
public class ShortBlack extends Coffee {public ShortBlack() {setDescription("shortBlack");setPrice(4);}
}

装饰器子类:

public class Soy extends Decorator {public Soy(Drink drink) {super(drink);setDescription("豆浆");setPrice(1.5);}
}
public class Milk extends Decorator{public Milk(Drink drink) {super(drink);setDescription("牛奶");setPrice(2);}
}
public class Chocolate extends Decorator {public Chocolate(Drink drink) {super(drink);setDescription("巧克力");setPrice(3);}
}

Client调用:

public class Client {public static void main(String[] args) {// 两份巧克力+一份牛奶LongblackDrink order1 = new LongBlack();System.out.println("order1费用:" + order1.cost());System.out.println("order1描述:" + order1.getDescription());order1 = new Milk(order1);System.out.println("order1加一份牛奶费用:" + order1.cost());System.out.println("order1加一份牛奶描述:" + order1.getDescription());order1 = new Chocolate(order1);System.out.println("order1加一份牛奶,加一份巧克力费用:" + order1.cost());System.out.println("order1加一份牛奶,加一份巧克力描述:" + order1.getDescription());order1 = new Chocolate(order1);System.out.println("order1加一份牛奶,加两份巧克力费用:" + order1.cost());System.out.println("order1加一份牛奶,加两份巧克力描述:" + order1.getDescription());System.out.println("==============================");Drink order2 = new Decaf();System.out.println("无因咖啡费用:" + order2.cost());System.out.println("无因咖啡描述:" + order2.getDescription());order2 = new Milk(order2);System.out.println("无因咖啡,加一份牛奶费用:" + order2.cost());System.out.println("无因咖啡,加一份牛奶描述:" + order2.getDescription());}
}

结果打印:

order1费用:5.0
order1描述:longBlack
order1加一份牛奶费用:7.0
order1加一份牛奶描述:牛奶 2.0 && longBlack
order1加一份牛奶,加一份巧克力费用:10.0
order1加一份牛奶,加一份巧克力描述:巧克力 3.0 && 牛奶 2.0 && longBlack
order1加一份牛奶,加两份巧克力费用:13.0
order1加一份牛奶,加两份巧克力描述:巧克力 3.0 && 巧克力 3.0 && 牛奶 2.0 && longBlack
==============================
无因咖啡费用:1.0
无因咖啡描述:无因咖啡
无因咖啡,加一份牛奶费用:3.0
无因咖啡,加一份牛奶描述:牛奶 2.0 && 无因咖啡

3.小结

  • 装饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

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

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

相关文章

「Conda」在Linux系统中安装Conda环境管理器

在Linux系统中安装Conda环境管理器是一个相对简单的过程。 1. 准备工作 确保你的Linux系统已经更新到最新版本,并安装了基本的开发工具和库。打开终端,执行以下命令: sudo apt-get update sudo apt-get upgrade sudo apt-get install build-essential2. 安装Miniconda或An…

GB35114控制信令认证流程

GB35114控制信令认证说明: 注册成功后,信令发送方与信令接收方进行交互时,采用基于带密钥的杂凑方式保障信令来源安 全。对除REGISTER消息以外的消息做带密钥的杂凑。启用Date字段,扩展信令消息头域,在头域中 增加 Note 字 段 (值 为 Digest…

项目经理到底要不要考PMP?

在接待PMP学员中我惊讶地发现,不仅是项目经理,连开发、测试、产品、运营、销售、甚至财务团队的朋友们也都在积极备考。他们考证的原因主要有这几点: 1,职业发展:希望在职业生涯中晋升或转型到项目管理角色的朋友来说…

Spring MVC 全注解开发

1. Spring MVC 全注解开发 文章目录 1. Spring MVC 全注解开发2. web.xml 文件 的替代2.1 Servlet3.0新特性2.2 编写 WebAppInitializer 3. Spring MVC的配置3.1 Spring MVC的配置:开启注解驱动3.2 Spring MVC的配置:视图解析器3.3 Spring MVC的配置&…

SourceTree rebase(变基)的使用

参考资料 【Sourcetree】コミットを一つにまとめる【Sourcetree】リベースする 目录 前提0.1 merge与rebase0.2 merge合并分支0.3 rebase合并分支0.4 💥超级注意事项💥 一. 代码已提交,未推送,交互式变基1.1 通过SourceTree操作1…

UWA学堂上新|服务器AOI(Area Of Interest)算法和功能实现

课程是《基于.NetCore开发MMORPG分布式游戏服务器》系列课程第6节,本系列课程旨在帮助大家从零开始搭建商业化MMORPG的分布式服务器框架,包括不同种类服务器的线程模型,如中心服务器、网关服务器、游戏服务器、寻路服务器等,并讲解…

PICO,迷途VR?

随着科技的持续向前发展,越来越多的智能可穿戴设备涌现出来。除了最为大众所熟知的智能手环、智能手表之外,VR设备同样是可穿戴设备领域的一大细分领域,不少巨头都在VR领域有所布局。 回溯过往可知,VR并非新鲜事物,早…

【NLP实战】基于TextCNN的新闻文本分类

TextCNN文本分类在pytorch中的实现 基于TextCNN和transformers.BertTokenizer的新闻文本分类实现,包括训练、预测、数据加载和准确率评估。 目录 项目代码TextCNN网络结构相关模型仓库准备工作项目调参预测与评估 1.项目代码 https://github.com/NeoTse0622/Te…

怎么选流量套餐最划算呢,这篇文章建议收藏!

据小编了解,现在大多数用户手上都不止一张SIM卡,大部分都是双卡,甚至三卡了,那么,这些卡槽你真的利用对了吗? 这篇文章就告诉大家,如何更好的利用这两个卡槽,让你即省钱&#xff0c…

XML 验证器:确保数据完整性和准确性的关键工具

XML 验证器:确保数据完整性和准确性的关键工具 引言 在当今数字化时代,数据的有效管理和交换至关重要。XML(可扩展标记语言)作为一种用于存储和传输数据的语言,广泛用于各种应用程序和系统之间。为确保XML数据的完整…

vue3中常用组件封装及使用

vue3组件 文件上传属性与方法完整代码组件使用 文件上传 属性与方法 <!-- 属性1. multiple多选2. action上传文件服务器地址3. before-upload上传前校检格式和大小4. file-list上传的文件列表5. limit数量限制6. on-error上传失败触发7. on-exceed文件个数超出触发8. on-s…

(02)Unity使用在线AI大模型(调用Python)

目录 一、概要 二、改造Python代码 三、制作Unity场景 一、概要 查看本文需完成&#xff08;01&#xff09;Unity使用在线AI大模型&#xff08;使用百度千帆服务&#xff09;的阅读和实操&#xff0c;本文档接入指南的基础上使用Unity C#调用百度千帆大模型&#xff0c;需要…

十五、C++11常用新特性—Lambda表达式

1.基本 这个好像是很好用的&#xff0c;其有以下有点&#xff1a; 声明式的编程风格&#xff1a;直接匿名定义目标函数或函数对象&#xff0c;不需要额外写一个命名函数或函数对象。简洁&#xff1a;避免了代码膨胀和功能分散&#xff0c;让开发更加高效。在需要的时间和地点…

Sentieon应用教程 | 唯一分子标识符(UMI)

介绍 本文介绍了使用Sentieon工具处理下一代测序数据的方法&#xff0c;同时利用分子条码信息&#xff08;也称为唯一分子索引或UMI&#xff09;。分子条码可以在测序之前在模板DNA分子的末端引入唯一标签&#xff0c;从而大大减少PCR重复和测序错误对变异调用过程的影响。 S…

影视迷必备:揭秘高效影视app开发幕后

影视迷必备的高效影视APP开发幕后涉及多个关键环节&#xff0c;从需求分析、规划设计、技术开发到测试上线&#xff0c;再到后续的运营与维护&#xff0c;每一个环节都至关重要。 一、需求分析 在开发影视APP之前&#xff0c;首要任务是进行深入的需求分析。这一阶段的主要目标…

CSS选择器(1)

以内部样式表编写CSS选择器&#xff0c;其主要编写在<head></head>元素里&#xff0c;通过<style></style>标签来定义内部样式表。 基本语法为&#xff1a; 选择器{ 声明块 } 声明块&#xff1a;是由一对大括号括起来&#xff0c;声明块中是一个一个的…

python-矩阵加法(赛氪OJ)

[题目描述] 输入两个 n 行 m 列的矩阵 A 和 B &#xff0c;输出它们的和 AB。矩阵加法的规则是两个矩阵中对应位置的值进行加和&#xff0c;具体参照样例。输入&#xff1a; 输入共 2⋅n1 行&#xff0c;第一行包含两个整数 n 和 m&#xff0c;表示矩阵的行数和列数 (1≤n,m≤1…

艺术创作的新维度:yicaiai照片风格化

艺术创作的新维度&#xff1a;yicaiai照片风格化 一、用户友好的设计理念 1.1 yicaiai照片风格化的核心设计理念 yicaiai平台以其创新的AI技术&#xff0c;颠覆了传统照片处理的方式&#xff0c;将艺术与科技完美融合。其核心设计理念在于赋予普通照片无尽的艺术潜力&#xf…

Python面试题:如何在 Python 中实现一个简单的 Web 服务器?

自动化测试的框架和技术体系 引言 自动化测试是现代软件开发流程中不可或缺的一部分。通过自动化测试&#xff0c;可以显著提高测试效率、覆盖范围和测试的可靠性&#xff0c;减少人为错误。本文将详细介绍常见的自动化测试框架和技术体系&#xff0c;涵盖单元测试、集成测试…