设计模式详解(十)——装饰器模式

装饰器模式简介

装饰器模式定义
从代码层面而言,是对类的一个扩展或者是修饰,从传统方法而言,我们可以使用继承来对某一个类进行扩展,但是往往会导致会出现非常多的子类,如果我们要想避免这种情况,那么我们就可以使用设计模式中的——装饰器模式。
装饰器模式也称为包装模式是指在不改变现有对象结构的情况下,动态地给该对象增加一些职责,即增加其额外功能,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。装饰器模式的核心是功能扩展,使用装饰器模式可以透明且动态地扩展类的功能。简单来说,就是一个东西,然后不断在该东西上添加符合该物件的功能,进行扩展的模式

装饰器模式包含以下角色:

  • 抽象组件(Component): 可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为;
  • 具体组件(ConcreteComponent): 实现/继承抽象组件的一个具体对象,也即被装饰对象;
  • 抽象装饰器(Decorator): 通用的装饰具体组件的装饰器,其内部必然有一个属性指向抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个抽象组件,这是强制的通用行为;
  • 具体装饰器(ConcreteDecorator): 实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。理论上,每个具体装饰器都扩展了 抽象组件对象的一种功能

装饰器模式优缺点:
优点:

  1. 装饰器模式可拓展性强,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
  2. 易于维护,哪个功能出问题直接找相关代码即可
  3. 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
  4. 装饰器模式完全遵守开闭原则

缺点:

  1. 装饰器模式会增加许多子类,会使得代码变得繁多增加程序的复杂性
  2. 动态装饰在多层装饰时会更复杂

使用场景

  1. 用于扩展一个类的功能,或者给一个类添加附加职责
  2. 动态的给一个对象添加功能,这些功能可以再动态的被撤销
  3. 需要为一批平行的兄弟类进行改装或者加装功能
  4. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  5. 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时

以下举一个装饰器模式的例子:
比如平时我们都肯定喝过奶茶,奶茶肯定有很多种,而且点的奶茶,还可以加料,比如加珍珠,加椰果之类的。这就可以用装饰器模式处理了。

创建Component对象,规定为MilkTea,行为功能为输出名字和输出价格:

public abstract class MilkTea {protected abstract String getName();protected abstract int getPrice();
}

创建ConcreteComponent,规定为焦糖奶茶:

public class CaramelMilkTea extends MilkTea {@Overrideprotected String getName() {return "焦糖奶茶";}@Overrideprotected int getPrice() {return 20;}
}

创建Decorator对象,进行静态代理

public abstract class Add extends MilkTea {private final MilkTea milkTea;public Add(MilkTea milkTea) {this.milkTea = milkTea;}@Overrideprotected String getName() {return this.milkTea.getName();}@Overrideprotected int getPrice() {return this.milkTea.getPrice();}
}

创建多个ConcreteDecorator对象,实现功能扩展(加装饰球、加缎带)

public class Pearl extends Add {public Pearl(MilkTea milkTea) {super(milkTea);}@Overrideprotected String getName() {return super.getName() + ",加了珍珠";}@Overrideprotected int getPrice() {return super.getPrice() + 5;}
}
public class Coconut extends Add {public Coconut(MilkTea milkTea) {super(milkTea);}@Overrideprotected String getName() {return super.getName() + ",加了椰果";}@Overrideprotected int getPrice() {return super.getPrice() + 3;}
}

测试类:

public class test {public static void main(String[] args) {System.out.println("点一杯焦糖奶茶");MilkTea caramelMilkTea = new CaramelMilkTea();System.out.println(caramelMilkTea.getName() + ",总价格:" + caramelMilkTea.getPrice() + "元");System.out.println("加珍珠");caramelMilkTea = new Pearl(caramelMilkTea);System.out.println(caramelMilkTea.getName() + ",总价格:" + caramelMilkTea.getPrice() + "元");System.out.println("再加椰果");caramelMilkTea = new Coconut(caramelMilkTea);System.out.println(caramelMilkTea.getName() + ",总价格:" + caramelMilkTea.getPrice() + "元");}
}

输出结果如下所示:

点一杯焦糖奶茶
焦糖奶茶,总价格:20元
加珍珠
焦糖奶茶,加了珍珠,总价格:25元
再加椰果
焦糖奶茶,加了珍珠,加了椰果,总价格:28

从结果可以看成功根据需求,获取到了一杯焦糖奶茶加了珍珠和椰果,并计算出价格。

总而言之:
在实际项目中,装饰器模式的运用可以通过遵循一些设计原则和最佳实践来更好地实现。首先,我们应该保持设计简单,避免过度使用装饰器,以及遵循面向对象的基本设计原则。其次,我们应该尽可能地避免重复代码和保持代码的可读性和可维护性。最后,我们应该考虑设计模式的上下文和这些模式的适用性,以及不同场景下应用不同设计模式的灵活性。
装饰器模式满足了设计原则的单一职责原则,可以在自己的装饰类中完成一些额外的功能逻辑拓展,而且不会影响到被装饰的主类,同时可以按需在运行时添加或删除这部分逻辑。
装饰器模式的重点是对抽象类接口方式的使用,同时被实现的接口可以通过构造函数传递其类,由此增加扩展性,并重写方法中可以通过父类实现的功能。


以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git

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

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

相关文章

深入理解 Django 单元测试

在现代软件开发流程中,单元测试是确保代码质量和可维护性的关键组成部分。对于使用 Django 框架的项目来说,Django 提供了一套强大的测试工具来帮助开发者编写和运行单元测试。本文将深入探讨 Django 中的单元测试,包括测试原理、编写测试用例…

uniapp——项目02

分类 创建cate分支 渲染分类页面的基本结构 效果页面,包含左右两个滑动区. 利用提供的api获取当前设备的信息。用来计算窗口高度。可食用高度就是屏幕高度减去上下导航栏的高度。 最终效果: 每一个激活项都特殊背景色,又在尾部加了个红条一样的东西。 export d…

python3GUI--QQ音乐By:PyQt5(附下载地址)

文章目录 一.前言二.展示0.播放页1.主界面1.精选2.有声电台3.排行4.歌手5.歌单 2.推荐3.视频1.视频2.分类3.视频分类 4.雷达5.我喜欢1.歌曲2.歌手 6.本地&下载7.最近播放8.歌单1.一般歌单2.自建歌单3.排行榜 9.其他1.搜索词推荐2.搜索结果 三&#x…

ElasticSearch7.x - HTTP 操作 - 文档操作

创建文档(添加数据) 索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数 据库中的表数据,添加的数据格式为 JSON 格式 向 ES 服务器发 POST 请求 :http://192.168.254.101:9200/shopping/_doc 请求体内容为: {"title":"小…

智慧城市建设解决方案分享【完整】

文章目录 第1章 前言第2章 智慧城市建设的背景2.1 智慧城市的发展现状2.2 智慧城市的发展趋势 第3章 智慧城市“十二五”规划要点3.1 国民经济和社会发展“十二五”规划要点3.2 “十二五”信息化发展规划要点 第4章 大数据:智慧城市的智慧引擎4.1 大数据技术—智慧城…

智慧城市照明为城市节能降耗提供支持继电器开关钡铼S270

智慧城市照明:为城市节能降耗提供支持——以钡铼技术S270继电器开关为例 随着城市化进程的加速,城市照明系统的需求也日益增长。与此同时,能源消耗和环境污染问题日益严重,使得城市照明的节能减排成为重要议题。智慧城市照明系统…

Linux技能篇-yum源搭建(本地源和公网源)

文章目录 前言一、yum源是什么?二、使用镜像搭建本地yum源1.搭建临时仓库第一步:挂载系统ios镜像到虚拟机第二步:在操作系统中挂载镜像第三步:修改yum源配置文件 2.搭建本地仓库第一步:搭建临时yum源来安装httpd并做文…

javaEE案例,前后端交互,计算机和用户登录

加法计算机,前端的代码如下 : 浏览器访问的效果如图 : 后端的代码如下 再在浏览器进行输入点击相加,就能获得结果 开发中程序报错,如何定位问题 1.先定位前端还是后端(通过日志分析) 1)前端 : F12 看控制台 2)后端 : 接口,控制台日志 举个例子: 如果出现了错误,我们就在后端…

如何查看网站的https的数字证书

如题 打开Chrome浏览器,之后输入想要抓取https证书的网址,此处以知乎为例点击浏览器地址栏左侧的锁的按钮,如下图 点击“连接是安全的”选项,如下图 点击“证书有效”选项卡,如下图 查看基本信息和详细信息 点击详细信…

linux内核基本知识一

1.ioremap映射访问和使用in/out直接访问的区别与联系 linux中使用ioremap映射访问和使用in/out直接访问的区别与联系??? 在Linux内核中,ioremap()函数用于将物理地址映射到虚拟地址空间,以便在内核中访问设备寄存器或…

25期代码随想录算法训练营第十四天 | 二叉树 | 层序遍历(10道题)、226.翻转二叉树 、101.对称二叉树 2

目录 层序遍历 10226.翻转二叉树101.对称二叉树 2 层序遍历 10 链接 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right clas…

C/C++数字判断 2021年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C数字判断 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C数字判断 2021年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入一个字符,如何输入的字符是数字&#x…

Spark的转换算子和操作算子

1 Transformation转换算子 1.1 Value类型 1)创建包名:com.shangjack.value 1.1.1 map()映射 参数f是一个函数可以写作匿名子类,它可以接收一个参数。当某个RDD执行map方法时,会遍历该RDD中的每一个数据项,并依次应用f函…

Mac下eclipse配置JDK

一、配置JDK,需要电脑下载Java并且配置环境 Mac环境配置(Java)----使用bash_profile进行配置(附下载地址) (1)、左上角找到“Eclipse”-->“Preferences...” (2)、找到“Java”-->“Installde JREs”-->界…

S7-1200PLC和SMART PLC开放式以太网通信(UDP双向通信)

S7-1200PLC的以太网通信UDP通信相关介绍还可以参考下面文章链接: 博途PLC开放式以太网通信TRCV_C指令应用编程(运动传感器UDP通信)-CSDN博客文章浏览阅读2.8k次。博途PLC开放式以太网通信TSENG_C指令应用,请参看下面的文章链接:博途PLC 1200/1500PLC开放式以太网通信TSEND_…

AI:73-结合语法知识的神经机器翻译研究

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

AM@多元函数极值存在定理@条件极值

文章目录 abstract多元函数极值存在定理极值求解求解步骤驻点部分偏导不存在的点 例多元函数最值例 条件极值条件极值转为无条件极值极值必要条件拉格朗日乘数法推广例 abstract 多元函数极值和最值多元函数极值存在定理条件极值 多元函数极值存在定理 本定理给出极值存在充…

HTTPS的工作流程

. HTTPS是什么? https是应用层中的一个协议,是在http协议的基础上引入的一个加密层。 为什么需要HTTPS 由于http协议内容都是按照文本的方式明文传输的,这就导致传输过程中会出现一些被篡改的情况。运营商劫持事件最开始百度,…

云栖大会丨桑文锋:打造云原生数字化客户经营引擎

近日,2023 云栖大会在杭州举办。今年云栖大会回归了 2015 的主题:「计算,为了无法计算的价值」。神策数据创始人 & CEO 桑文锋受邀出席「生态产品与伙伴赋能」技术主题,并以「打造云原生数字化客户经营引擎」为主题进行演讲。…

CSS特效006:绘制不断跳动的心形

css实战中,怎么绘制不断跳动的心形呢? 绘图的时候主要用到了transform: rotate(-45deg); transform-origin: 0 100%; transform: rotate(45deg); transform-origin: 100% 100%; 动画使用keyframes 时间上为infinite。 效果图 源代码 /* * Author: 大剑…