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

设计模式(十一)----结构型模式之装饰者模式

1、概述

我们先来看一个快餐店的例子。

快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。

使用继承的方式存在的问题:

  • 扩展性不好

    如果要再加一种配料(火腿肠),我们就会发现需要给FriedRice和FriedNoodles分别定义一个子类。如果要新增一个快餐品类(炒河粉)的话,就需要定义更多的子类。

  • 产生过多的子类

定义:

指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。

2、结构

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

  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。上图中的抽象快餐类

  • 具体构件(ConcreteComponent)角色 :实现抽象构件,通过装饰角色为其添加一些职责。炒米粉炒面等具体角色

  • 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。加鸡蛋加火腿抽象类

  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。具体加鸡蛋还是加火腿

3、案例

我们使用装饰者模式对快餐店案例进行改进,体会装饰者模式的精髓。

类图如下:

代码如下:

//快餐接口
public abstract class FastFood {private float price;private String desc;
​public FastFood() {}
​public FastFood(float price, String desc) {this.price = price;this.desc = desc;}
​public void setPrice(float price) {this.price = price;}
​public float getPrice() {return price;}
​public String getDesc() {return desc;}
​public void setDesc(String desc) {this.desc = desc;}
​public abstract float cost();  //获取价格
}
​
//炒饭
public class FriedRice extends FastFood {
​public FriedRice() {super(10, "炒饭");}
​public float cost() {return getPrice();}
}
​
//炒面
public class FriedNoodles extends FastFood {
​public FriedNoodles() {super(12, "炒面");}
​public float cost() {return getPrice();}
}
​
//配料类  装饰者
public abstract class Garnish extends FastFood {
​private FastFood fastFood;
​public FastFood getFastFood() {return fastFood;}
​public void setFastFood(FastFood fastFood) {this.fastFood = fastFood;}
​public Garnish(FastFood fastFood, float price, String desc) {super(price,desc);this.fastFood = fastFood;}
}
​
//鸡蛋配料
public class Egg extends Garnish {
​public Egg(FastFood fastFood) {super(fastFood,1,"鸡蛋");}
​public float cost() {return getPrice() + getFastFood().getPrice();}
​@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}
​
//培根配料
public class Bacon extends Garnish {
​public Bacon(FastFood fastFood) {
​super(fastFood,2,"培根");}
​@Overridepublic float cost() {return getPrice() + getFastFood().getPrice();}
​@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}
​
//测试类
public class Client {public static void main(String[] args) {//点一份炒饭FastFood food = new FriedRice();
​System.out.println(food.getDesc() + "  " + food.cost() + "元");
​System.out.println("===============");
​//在上面的炒饭中加一个鸡蛋food = new Egg(food);System.out.println(food.getDesc() + "  " + food.cost() + "元");
​System.out.println("================");//再加一个鸡蛋food = new Egg(food);System.out.println(food.getDesc() + "  " + food.cost() + "元");
​System.out.println("================");food = new Bacon(food);System.out.println(food.getDesc() + "  " + food.cost() + "元");}
}

测试结果

好处:

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

  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

4、使用场景

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    不能采用继承的情况主要有两类:

    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;

    • 第二类是因为类定义不能继承(如final类)

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  • 当对象的功能要求可以动态地添加,也可以在动态地撤销时。比如鸡蛋已经卖完了,这时候只需要移除鸡蛋类就可以了。

5、JDK源码解析

IO流中的包装类使用到了装饰者模式。BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。

我们以BufferedWriter举例来说明,先看看如何使用BufferedWriter

public class Demo {public static void main(String[] args) throws Exception{//创建BufferedWriter对象//创建FileWriter对象FileWriter fw = new FileWriter("C:\\Users\\Think\\Desktop\\a.txt");BufferedWriter bw = new BufferedWriter(fw);
​//写数据bw.write("hello Buffered");
​bw.close();}
}

使用起来感觉确实像是装饰者模式,接下来看它们的结构:

小结:

BufferedWriter使用装饰者模式对Writer子实现类进行了增强,添加了缓冲区,提高了写数据的效率。

相关文章:

设计模式(十一)----结构型模式之装饰者模式

1、概述 我们先来看一个快餐店的例子。 快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。 使用继承的方式存在的问题&…...

lighthouse的介绍和基本使用方法

Lighthouse简介 Lighthouse是一个开源的自动化性能测试工具,我们可以使用该功能检测我们的页面存在那些性能方面的问题,并会生成一个详细的性能报告来帮助我们来优化页面 使用方式 LH一共有四种使用方式 Chrome开发者工具Chrome扩展Node 命令行Node …...

分布式算法 - Raft算法

Paxos是出了名的难懂,而Raft正是为了探索一种更易于理解的一致性算法而产生的。它的首要设计目的就是易于理解,所以在选主的冲突处理等方式上它都选择了非常简单明了的解决方案。推荐阅读提示强烈推荐通过如下资料学习raft。 raft.github.io这里面有一个…...

Python|每日一练|链表|双指针|数组|递归|图算法|单选记录:删除链表的倒数第 N 个结点|下一个排列|迷宫问题

1、删除链表的倒数第 N 个结点(链表,双指针) 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 进阶:你能尝试使用一趟扫描实现吗? 示例 1: 输入:head …...

天线理论知识2——宽带天线介绍

系列文章目录 文章目录 系列文章目录前言一、行波天线1. 长导线天线2. V形天线二、螺旋天线三、八木-宇田天线前言 宽带天线指的是具有哦宽频带特性的天线,常见的宽带天线有行波天线,螺旋天线以及八木天线。 一、行波天线 长度为 l l l的中心馈电的线天线上的电流呈驻波分…...

【计组笔记05】计算机组成与原理之虚拟存储器、指令系统、中央处理器CPU

这篇文章,主要介绍计算机组成与原理之虚拟存储器、指令系统、中央处理器CPU。 目录 一、虚拟存储器 1.1、页式虚拟存储器 1.2、段式虚拟存储器 1...

多功能土壤速测仪功能介绍

大家好,今天给大家介绍一款多功能土壤速测仪,它由多功能速测仪主机、土壤墒情传感器、USB数据线、电源适配器、便携式手提箱等部分组成。速测主机配备有工业级液晶屏,大屏幕中文显示,使得测量参数,时间,设备…...

《设计模式》命令模式

《设计模式》命令模式 命令模式(Command Pattern)是一种行为型设计模式,它将请求和处理分开,使得请求发送者和接收者解耦,从而降低系统的耦合度。在命令模式中,请求被封装为一个独立的对象,并且…...

开源物联网平台有哪些?

目前市面上有许多开源物联网平台可供选择。以下是其中一些较为流行和知名的平台: Eclipse IoT:Eclipse IoT 是一个开源的物联网平台,旨在提供可扩展、灵活和高度集成的工具和框架,用于构建、部署和管理 IoT 解决方案。它包含多个…...

Tesla Autopilot,处理器和硬件

作者 | 初光 出品 | 车端 备注 | 转载请阅读文中版权声明 知圈 | 进“汽车电子与AutoSAR开发”群,请加微“cloud2sunshine” 总目录链接>> AutoSAR入门和实战系列总目录 Tesla MOdelS/X 中有 60 多个处理器。其他型号的处理器较少,但数量仍然不少…...

jianzhiOffer第二版难重点记录

04. 二维数组中的查找https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/ 思路:可以每层用以恶搞二分查找,优化思路:从左下角出发直接用二分。 ​​​​​​07. 重建二叉树https://leetcode.cn/problems/zhong-jian-er-cha…...

C语言 | 问题20230225

C语言 | 问题20230225 文章目录C语言 | 问题202302251.问题1无限循环2.问题2C 中的运算符优先级实例1:1.问题1 Which slice of the following code is NOT endless loop? 以下代码的哪一部分不是无限循环? A for (;(cgetchar())!\n; ) printf("*c&…...

【机器学习笔记】Python基础笔记

目录基础语法加载数据:pd.read_csv查看数据大小:shape浏览数据行字段:columns浏览少量数据:head()浏览数据概要:describe()基础功能语法缺省值去除缺失值:dropna按行删除:存在空值,即…...

js-DOM03-DOM对CSS的操作

DOM对CSS的操作 - 读取和修改内联样式 - 使用style属性来操作元素的内联样式 - 读取内联样式: 语法:元素.style.样式名 - 例子: 元素.style.width 元素.style.…...

tun驱动之tun_init

tun驱动的初始化方法是tun_init。 static int __init tun_init(void) {int ret 0;pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);ret rtnl_link_register(&tun_link_ops);if (ret) {pr_err("Cant register link_ops\n");goto err_linkops;}re…...

模拟退火算法优化bp

%% 基于模拟退火遗传算法优化BP神经网络的钢带厚度预测 clear clc close all format short %% 加载训练数据 Xtrxlsread(train_data.xlsx); DDsize(Xtr,2); input_trainXtr(:,1:DD-1);% output_trainXtr(:,DD);% %% 加载测试数据 Xtexlsread(test_data.xlsx); input_testXte(…...

【NFC音乐相册】简易制作

欢迎来到 Claffic 的博客 💞💞💞 前言: NFC音乐相册在前段时间火了一把,想必大家都听过了,最近我刷到了这个东西,闲来无事就弄了几个,这篇博客就记录下制作工序。 注:我所…...

每日一题——L1-085 试试手气(15)

L1-085 试试手气 我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态,即它们朝上一面的点数,让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙,每次摇出的结果都满足以下两个条件:…...

FreeRTOS信号量

前面介绍过,队列(queue)可以用于传输数据:在任务之间,任务和中断之间。消息队列用于传输多个数据,但是有时候我们只需要传递一个状态,这个状态值需要用一个数值表示,比如&#xff1a…...

Leetcode.2385 感染二叉树需要的总时间

题目链接 Leetcode.2385 感染二叉树需要的总时间 Rating : 1711 题目描述 给你一棵二叉树的根节点 root,二叉树中节点的值 互不相同 。另给你一个整数 start。在第 0分钟,感染 将会从值为 start的节点开始爆发。 每分钟,如果节点…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...

[特殊字符] 手撸 Redis 互斥锁那些坑

&#x1f4d6; 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作&#xff0c;想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁&#xff0c;也顺便跟 Redisson 的 RLock 机制对比了下&#xff0c;记录一波&#xff0c;别踩我踩过…...

SpringCloud优势

目录 完善的微服务支持 高可用性和容错性 灵活的配置管理 强大的服务网关 分布式追踪能力 丰富的社区生态 易于与其他技术栈集成 完善的微服务支持 Spring Cloud 提供了一整套工具和组件来支持微服务架构的开发,包括服务注册与发现、负载均衡、断路器、配置管理等功能…...