Gof23设计模式之装饰者模式

1.概述

定义

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

例子

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

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

2.结构

装饰模式中的角色:

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

3.类图

在这里插入图片描述

4.代码

抽象构件角色

/*** @author 晓风残月Lx* @date 2023/7/3 20:14*      快餐类(抽象构件角色)*/
public abstract class FastFood {private float price;private String desc;public FastFood(float price, String desc) {this.price = price;this.desc = desc;}public FastFood() {}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}public abstract float cost();}

具体构建角色

/*** @author 晓风残月Lx* @date 2023/7/3 20:18*      炒面(具体构建角色)*/
public class FriedNoodles extends FastFood{public FriedNoodles() {super(12, "炒面");}@Overridepublic float cost() {return getPrice();}
}/*** @author 晓风残月Lx* @date 2023/7/3 20:16*      炒饭类(具体构件角色)*/
public class FriedRice extends FastFood {public FriedRice() {super(10,"炒饭");}@Overridepublic float cost() {return getPrice();}}

抽象装饰角色

/*** @author 晓风残月Lx* @date 2023/7/3 20:21*      装饰者类(抽象装饰角色)*/
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;}}

具体装饰角色

/*** @author 晓风残月Lx* @date 2023/7/3 20:27*      鸡蛋类(具体装饰角色)*/
public class Egg extends Garnish {public Egg(FastFood fastFood) {super(fastFood, 1, "鸡蛋");}@Overridepublic float cost() {// 计算价格return getPrice() + getFastFood().cost();}@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}/*** @author 晓风残月Lx* @date 2023/7/3 20:30* 培根类(具体装饰角色)*/
public class Bacon extends Garnish {public Bacon(FastFood fastFood) {super(fastFood, 2, "培根");}@Overridepublic float cost() {return getPrice() + getFastFood().cost();}@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}
/*** @author 晓风残月Lx* @date 2023/7/3 20:31*/
public class Client {public static void main(String[] args) {// 点一份炒饭FastFood friedRice = new FriedRice();System.out.println(friedRice.getDesc() + ":" + friedRice.cost());// 加份鸡蛋friedRice = new Egg(friedRice);System.out.println(friedRice.getDesc() + ":" + friedRice.cost());// 再加份鸡蛋friedRice = new Egg(friedRice);System.out.println(friedRice.getDesc() + ":" + friedRice.cost());// 再加份培根friedRice = new Bacon(friedRice);System.out.println(friedRice.getDesc() + ":" + friedRice.cost());}
}

在这里插入图片描述

好处:

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

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

5.使用场景

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
    不能采用继承的情况主要有两类:
    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如final类)
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

6.JDK源码分析

说到装饰者模式,其实很明显IO流中的包装类使用到了装饰者模式。
BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。

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

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

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

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

相关文章

springmvc相关知识点记录

1、若依框架:v—haspermi条件写上就要保证内容包含在getinfo的列表里面,否则不显示按钮 2、当elmentui中只有一个input的时候,空值按enter键会刷新整个页面,需要在form标签中加上submit.native.prevent来阻止刷新页面 3、 spri…

VBA小工具:EXCEL如何批量给每行下面插入n个空行?

目录 1EXCEL本身的方法 2 VBA实现1: 2.1 粗糙代码 2.2 需要注意的问题 3 VBA实现2: 3.1 改进代码:根据用户自己先选中的区域,进行插入空行操作。 3.1.1 用户可在EXCEL里选中区域,而不是改VBA代码 3.1.2 自动识…

js逆向补环境-调试工具vscode与nodejs使用之无环境联调

目录 一、啊哈一、Nodejs安装1、nodejs最新版本的安装(windows)2、旧版nodejs更新成最新版本(windows)3、nodejs安装(linux) 二、vscode安装使用(windows)1、下载安装vscode2、vscode运行插件Code Runner安…

微信小程序视图层莫名出现”竖线“

写完视图层后&#xff0c;发现页面上莫名其妙的出现了一些“竖线”&#xff0c;如下图所示&#xff1a; 这段html代码是这样写的&#xff1a; <view class"other-des"><view class"section"><text class"section-num">{{cou…

Python实现PSO粒子群优化算法优化Catboost回归模型(CatBoostRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 PSO是粒子群优化算法&#xff08;Particle Swarm Optimization&#xff09;的英文缩写&#xff0c;是一…

抖音seo源码开发部署技术分享(一)

目录 开发概述 自研开发者介绍 开发要求&#xff1a; 技术开发布局 源码部署及搭建分享 部署环境搭建 代码开发示例 请求样例 响应样例&#xff1a; 代码展示样例 开发概述 开放平台基于开发者诉求和相关平台规则&#xff0c;提供了两种开放模式&#xff1a;能力开放…

Python零基础入门(七)——Python中的选择和循环语句

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python入门专栏&#xff1a;《Python入门》欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; 码字不易&#xff0c;如果觉得文章不…

day69_Vue进阶

今日内容 零、 复习昨日 零、 复习昨日 nginx 静态服务器(动静分离)反向代理服务器(代理后端服务器)负载均衡异步 前端工程化 —> java代码工程 一、使用Vue-Cli搭建Vue项目 1.1 什么是vue-cli cli: Command Line 命令行工具&#xff0c;vue-cli就是vue的命令行工具&#xf…

LeetCode[面试题17.14]最小的K个数

难度&#xff1a;中等 题目&#xff1a; 设计一个算法&#xff0c;找出数组中最小的k个数。以任意顺序返回这k个数均可。 示例&#xff1a; 输入&#xff1a; arr [1,3,5,7,2,4,6,8], k 4 输出&#xff1a; [1,2,3,4]提示&#xff1a; 0 < len(arr) < 1000000 <…

开源教育对话大模型 EduChat

文章目录 一、&#x1f680; 前言二、&#x1f916; 本地部署三、&#x1f468;‍&#x1f4bb; 使用示例四、&#x1f50e; 总结 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、&#x1f680; 前言 教育是一项对人类身心发展产生影响的社会实践…

磁盘与文件系统管理

磁盘结构及分区表示 硬盘 Hard Disk Drive &#xff0c;简称 HDD 是计算机常用的存储设备之一。 1 磁盘基础 1.1 硬盘的结构 1.1.1 数据结构 ①扇区&#xff1a;磁盘上的每个磁道被等分为若干个弧段,这些弧段便是硬盘的扇区(Sector)。硬盘的第一个扇区&#xff0c;叫做引导…

easyupload

红框位置是上传后的提示 依次尝试上传&#xff0c;发现php,phtml.php3&#xff0c;php5&#xff0c;双写等都不行 .htaccess文件也不行 尝试.php. 绕过 (windows中会把后缀名最后的空格和. 省略&#xff0c;即上传.php.绕过后会变为.php) 加入图片头的php文件也不行 但是加入文…