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

【Java设计模式】八、装饰者模式

文章目录

  • 0、背景
  • 1、装饰者模式
  • 2、案例
  • 3、使用场景
  • 4、源码中的实际应用

0、背景

有个快餐店,里面的快餐有炒饭FriedRice 和 炒面FriedNoodles,且加配菜后总价不一样,计算麻烦。如果单独使用继承,那就是:

在这里插入图片描述

类爆炸不说,再来个炒河粉,就发现这样写扩展性很差。

1、装饰者模式

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

  • 抽象构件:具体构件的规范接口
  • 具体构件:被装饰(被增加功能)的原始对象
  • 抽象装饰:继承抽象构件
  • 具体装饰:实现抽象装饰,给具体构件对象添加功能

总之,用于动态扩展一个类的功能(增强目标对象),而非使用继承

2、案例

在这里插入图片描述

定义快餐类(抽象构件):

//快餐接口
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public abstract class FastFood {private float price;private String desc;public abstract float cost();  //获取价格
}

定义炒饭、炒面类(具体的构件)

//炒饭
public class FriedRice extends FastFood {public FriedRice() {super(10, "炒饭");    //调用父类的构造方法,给炒饭的价格和描述赋值,即一碗炒饭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,"鸡蛋");    //一个鸡蛋一块钱 + 一份快餐}@Overridepublic 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("========");//点一份加鸡蛋的炒饭FastFood food1 = new FriedRice();food1 = new Egg(food1);   妙!//花费的价格System.out.println(food1.getDesc() + " " + food1.cost() + "元");System.out.println("========");//点一份加培根的炒面FastFood food2 = new FriedNoodles();food2 = new Bacon(food2); 妙!//花费的价格System.out.println(food2.getDesc() + " " + food2.cost() + "元");}
}

后续如果需求变动,要加一个新配料:火腿,那就定义一个类去继承Garnish类即可。且任何配料可以自由搭配任何主食(组合不同的装饰者对象),这比排列组合写出n个子类好多了。继承是静态的附加责任,装饰者则是动态的附加责任。

3、使用场景

不能采用继承的方式对已有功能进行扩充时,可用装饰者模式。比如:

  • 类被final修饰,不能被继承
  • 扩展项目太多,用继承会子类爆炸
  • 某些功能需要支持动态添加和动态撤销

4、源码中的实际应用

JDK中BufferedWriter等包装类,用到了装饰者模式,对Writer类进行了增强

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();}
}

在这里插入图片描述

相关文章:

【Java设计模式】八、装饰者模式

文章目录 0、背景1、装饰者模式2、案例3、使用场景4、源码中的实际应用 0、背景 有个快餐店,里面的快餐有炒饭FriedRice 和 炒面FriedNoodles,且加配菜后总价不一样,计算麻烦。如果单独使用继承,那就是: 类爆炸不说&a…...

python INI文件操作与configparser内置库

目录 INI文件 configparser内置库 类与方法 操作实例 导入INI 查询所有节的列表 判断某个节是否存在 查询某个节的所有键的列表 判断节下是否存在某个键 增加节点 删除节点 增加节点的键 修改键值 保存修改结果 获取键值 获取节点所有键值 INI文件 即Initiali…...

软考笔记--软件系统质量属性

一.软件系统质量属性的概念 软件系统的质量就是“软件系统与明确地和隐含的定义的需求相一致的程度”。更具体地说,软件系统质量就是软件与明确地叙述的功能和性能需求文档中明确描述的开发标准以及任何专业开发的软件产品都应该具有的隐含特征相一致的程度。从管理…...

新型设备巡检方案-手机云巡检

随着科技的不断发展,设备巡检工作也在逐步向智能化、高效化方向转变。传统的巡检方式往往需要人工逐个设备检查,耗时耗力,效率低下,同时还容易漏检和误检。而新型设备巡检应用—手机蓝牙云巡检的出现,则为设备巡检工作…...

node.js 下 mysql2 的 CURD 功能极简封装

此封装适合于使用 SQL 直接操作数据库的小型后端项目,更多功能请查阅MySQL2官网 // 代码保存到单独的 js 文件const mysql require(mysql2/promise)const debug true let conn/*** 执行 SQL 语句* param {String} sql* param {*} params* returns {Array}*/ const…...

Cloud-Eureka服务治理-Ribbon负载均衡

构建Cloud父工程 父工程只做依赖版本管理 不引入依赖 pom.xml <packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEA…...

Northwestern University-844计算机科学与技术/软件工程-机试指南【考研复习】

本文提到的西北大学是位于密歇根湖泊畔的西北大学。西北大学&#xff08;英语&#xff1a;Northwestern University&#xff0c;简称&#xff1a;NU&#xff09;是美国的一所著名私立研究型大学。它由九人于1851年创立&#xff0c;目标是建立一所为西北领地地区的人服务的大学。…...

【Linux的网络编程】

1、OSI的七层网络模型有哪些&#xff0c;每一层有什么作用&#xff1f; 答&#xff1a;&#xff08;1&#xff09;应用层&#xff1a;负责处理不同应用程序之间的通信&#xff0c;需要满足提供的协议&#xff0c;确保数据发送方和接收方的正确。 &#xff08;2&#xff09;表…...

vue-seamless-scroll 点击事件不生效

问题&#xff1a;在使用此插件时发现&#xff0c;列表内容前几行还是能正常点击的&#xff0c;但是从第二次出现的列表开始就没有点击事件了 原因&#xff1a;因为html元素是复制出来的&#xff08;滚动组件是将后面的复制出来一份&#xff0c;进行填铺页面&#xff0c;方便滚动…...

前端工程部署步骤小记

安装mqtt: “mqtt”: “^4.3.7”, npm install git panjiacheng 后台demo下载zip 1、npm install --registryhttps://registry.npmmirror.com 2、npm run dev 前端demo创建 1、安装npm 2、npm install vuenext 3、npm install -g vue/cli 查看版本 vue --version 4、更新插件…...

TS常见问题

文章目录 1. 什么是 TypeScript&#xff1f;它与 JavaScript 有什么区别&#xff1f;2. TS 泛型、接口、泛型工具record、Pick、Omit3. TS unknow和any的区别&#xff0c;如何告诉编译器unknow一定是某个类型&#xff1f;4. 元组与常规数组的区别5. 什么是泛型,有什么作用&…...

linux系统nginx常用命令

查nginx位置 find / -name nginx nginx目录&#xff1a;/usr/local/ 查看nginx进程号 ps -ef |grep nginx 停止进程 kill 2072 启动 ./sbin/nginx /usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf 启动并校验校验配置文件 ./sbin/nginx -t 看到如下显…...

MySQl基础入门③

上一遍内容 接下来我们都使用navicat软件来操作数据了。 1.新建数据库 先创建我门自己的一个数据库 鼠标右键点击bendi那个绿色海豚的图标&#xff0c;然后选择新建数据库。 数据库名按自己喜好的填&#xff0c;不要写中文&#xff0c; 在 MySQL 8.0 中&#xff0c;最优的字…...

idea Gradle 控制台中文乱码

如下图所示&#xff0c;idea 中的 Gradle 控制台中文乱码&#xff1a; 解决方法&#xff0c;如下图所示&#xff1a; 注意&#xff1a;如果你的 idea 使用 crack 等方式破解了&#xff0c;那么你可能需要在文件 crack-2023\jetbra\vmoptions\idea.vmoptions 中进行配置&#xf…...

嵌入式学习day31 网络

网络: 数据传输,数据共享 1.网络协议模型: OSI协议模型 应用层 实际发送的数据 表示层 发送的数据是否加密 会话层 是否建立会话连接 传输层 数据传输的方式&#xff08;数据报…...

Docker网络+原理+link+自定义网络

目录 一、理解Docker网络 1.1 运行tomcat容器 1.2 查看容器内部网络地址 1.3 测试连通性 二、原理 2.1 查看网卡信息 2.2 再启动一个容器测试网卡 2.3 测试tomcat01 和tomcat02是否可以ping通 2.4 只要删除容器,对应网桥一对就没了 2.5 结论 三、--link 3.…...

Effective C++ 学习笔记 条款16 成对使用new和delete时要采取相同形式

以下动作有什么错&#xff1f; std::string *stringArray new std::string[100]; // ... delete stringArray;每件事看起来都井然有序&#xff0c;使用了new&#xff0c;也搭配了对应的delete。但还是有某样东西完全错误&#xff1a;你的程序行为未定义。至少&#xff0c;str…...

PokéLLMon 源码解析(四)

.\PokeLLMon\poke_env\exceptions.py """ This module contains exceptions. """# 定义一个自定义异常类 ShowdownException&#xff0c;继承自内置异常类 Exception class ShowdownException(Exception):"""This exception is …...

区块链基础知识01

区块链&#xff1a;区块链技术是一种高级数据库机制&#xff0c;允许在企业网络中透明地共享信息。区块链数据库将数据存储在区块中&#xff0c;而数据库则一起链接到一个链条中。数据在时间上是一致的&#xff0c;在没有网络共识的情况下&#xff0c;不能删除或修改链条。 即&…...

YOLOv9(2):YOLOv9网络结构

1. 前言 本文仅以官方提供的yolov9.yaml来进行简要讲解。 讲解之前&#xff0c;还是要做一些简单的铺垫。 Slice层不做任何的操作&#xff0c;纯粹是做一个占位层。这样一来&#xff0c;在parse_model时&#xff0c;ch[n]可表示第n层的输出通道。 Detect和DDetect主要区别还…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...