装饰器模式详解(附代码案例和源码分析)

news/2025/1/18 2:01:40/

目录

装饰器模式的本质

装饰器模式和继承结构的对比

源码中IO流的继承结构

具体装饰器类

装饰器的组合应用

装饰器链的特点

代码案例

定义coffee类型

coffee的实现类 

装饰器抽象类

装饰器 - 季节限定

装饰器——加牛奶 

装饰器——加糖 

生成咖啡的简单工厂

咖啡制作服务(动态加功能)

装饰器模式的优点

装饰器模式的缺点


装饰器模式的本质

 装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它是一种用于代替继承的技术,通过组合的方式实现功能的扩展。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

多态与装饰器的结合优势,多态允许我们使用基类类型引用指向子类对象,这与装饰器模式完美契合。通过多态,我们可以在运行时动态决定使用哪些装饰器,而客户端代码无需关心具体实现细节。

装饰器模式和继承结构的对比

可能大家可能会有疑问,这装饰器功能不就和继承一样吗?为什么不直接用继承呢?还要装饰器模式有什么用?

现在可以想象一个场景,有一个coffee抽象类,下面有五个不同的coffee的实现类,若是我现在想给coffee类加上糖的功能,如果是用继承,那是不是要给这五个实现类都写子类实现。

如果过段时间,我又想添加一个新的功能呢?是不是又要给每个类写一个子类,这样的话会使这个继承结构变得非常冗杂。

那我现在做一个装饰器类,他的功能就是加糖,其中有个属性就是coffee抽象类,哪个coffee实现类想要有这个功能就直接赋值到装饰器类的属性就可以了,功能装饰器类都做了,那这样不就只用写一个类就好了?就避免了冗长的继承结构。

源码中IO流的继承结构

InputStream:字节输入流的抽象基类

OutputStream:字节输出流的抽象基类

FileInputStream:文件输入流,继承自InputStream

FileOutputStream:文件输出流,继承自OutputStream

ByteArrayInputStream:字节数组输入流,继承自InputStream

ByteArrayOutputStream:字节数组输出流,继承自OutputStream

FilterInputStream:过滤输入流,所有装饰器输入流的父类,持有一个InputStream引用,提供默认的装饰器实现

FilterOutputStream:过滤输出流,所有装饰器输出流的父类,持有一个OutputStream引用,提供默认的装饰器实现

具体装饰器类

BufferedInputStream:缓冲输入流,添加缓冲功能,提高读取效率,继承自FilterInputStream

BufferedOutputStream:缓冲输出流,添加缓冲功能,提高写入效率,继承自FilterOutputStream

DataInputStream:数据输入流,读取Java基本数据类型,支持基本类型的读取,继承自FilterInputStream

DataOutputStream:数据输出流,写入Java基本数据类型,支持基本类型的写入,继承自FilterOutputStream

装饰器的组合应用

基础流 + 缓冲:FileInputStream + BufferedInputStream

提供高效的文件读取

基础流 + 缓冲 + 数据类型处理:FileInputStream + BufferedInputStream + DataInputStream

装饰器链的特点

可以任意组合,每个装饰器,专注于一个功能,易于扩展新功能,优于继承的扩展方式

代码案例

定义coffee类型
java">// 1. 定义咖啡类型
public enum CoffeeType {ESPRESSO, LATTE, MOCHA
}
java">// 2. 扩展基础组件接口
public interface Coffee {String getDescription();double getCost();CoffeeType getType();void brew();  // 添加冲泡方法
}
coffee的实现类 
java">public class Espresso implements Coffee {@Overridepublic String getDescription() {return "Espresso";}@Overridepublic double getCost() {return 4.0;}@Overridepublic CoffeeType getType() {return CoffeeType.ESPRESSO;}@Overridepublic void brew() {System.out.println("Brewing strong espresso");}
}
java">public class Latte implements Coffee {@Overridepublic String getDescription() {return "Latte";}@Overridepublic double getCost() {return 5.0;}@Overridepublic CoffeeType getType() {return CoffeeType.LATTE;}@Overridepublic void brew() {System.out.println("Brewing latte with steamed milk");}
}
装饰器抽象类
java">public abstract class CoffeeDecorator implements Coffee {protected final Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;}// 默认实现委托给被装饰对象@Overridepublic String getDescription() {return decoratedCoffee.getDescription();}@Overridepublic double getCost() {return decoratedCoffee.getCost();}@Overridepublic CoffeeType getType() {return decoratedCoffee.getType();}@Overridepublic void brew() {decoratedCoffee.brew();}
}
装饰器 - 季节限定
java">public class SeasonalDecorator extends CoffeeDecorator {private final String season;public SeasonalDecorator(Coffee coffee, String season) {super(coffee);this.season = season;}@Overridepublic void brew() {super.brew();addSeasonalTouch();}private void addSeasonalTouch() {switch(season.toLowerCase()) {case "summer":System.out.println("Adding ice and mint leaf");break;case "winter":System.out.println("Adding cinnamon and nutmeg");break;}}
}
装饰器——加牛奶 
java">public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + ", with Milk";}@Overridepublic double getCost() {return decoratedCoffee.getCost() + 2.0;}// 特有方法public void addMilkFoam() {System.out.println("Adding milk foam");}
}
装饰器——加糖 
java">public class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + ", with Sugar";}@Overridepublic double getCost() {return decoratedCoffee.getCost() + 1.0;}// 特有方法public void mixSugar() {System.out.println("Mixing sugar thoroughly");}
}

 

生成咖啡的简单工厂
java">public class CoffeeFactory {public static Coffee createCoffee(CoffeeType type) {switch(type) {case ESPRESSO:return new Espresso();case LATTE:return new Latte();case MOCHA:return new MochaDecorator(new Espresso());default:throw new IllegalArgumentException("Unknown coffee type");}}
}
咖啡制作服务(动态加功能)
java">public class CoffeeService {public Coffee prepareCoffee(CoffeeType type, boolean withMilk, boolean withSugar, String season) {// 基础咖啡Coffee coffee = CoffeeFactory.createCoffee(type);// 根据条件动态添加装饰器if (withMilk) {coffee = new MilkDecorator(coffee);}if (withSugar) {coffee = new SugarDecorator(coffee);}// 季节性装饰if (season != null) {coffee = new SeasonalDecorator(coffee, season);}return coffee;}// 批量处理订单public List<Coffee> prepareOrders(List<CoffeeOrder> orders) {return orders.stream().map(order -> prepareCoffee(order.getType(),order.isWithMilk(),order.isWithSugar(),order.getSeason())).collect(Collectors.toList());}
}

通过多态,装饰器模式变得更加强大和灵活。它允许我们在运行时动态地组合不同的行为,同时保持代码的清晰和可维护性。这种组合为我们提供了一种优雅的方式来扩展对象的功能,而不需要创建大量的子类。

装饰器模式的优点

比继承更灵活:装饰类和被装饰类可以独立发展,不会相互耦合

动态扩展功能:通过组合不同的装饰器,可以实现不同的功能组合

符合开闭原则:增加新功能时,不需要修改原有代码,只需添加新的装饰类

具体组件类和装饰类可以独立变化:提供了比继承更多的灵活性

装饰器模式的缺点

会产生很多小对象:每个装饰器都要包装一个对象,会产生很多小对象

多层装饰比较复杂:如果层次过多,会使系统变得复杂

装饰器模式比继承更灵活,但也更容易出错,调试时寻找错误可能比较困难


http://www.ppmy.cn/news/1564034.html

相关文章

饭搭难点亮点

文章目录 难点不同请求响应头设置解决跨域问题切换餐厅头像的更改 亮点组件复用懒加载mixins复用用户交互体验 难点 不同请求响应头设置 大部分的请求头都是’Content-Type’&#xff1a;‘application/json’ 但也有少数请求需要的是’multipart/form-data’&#xff0c;例如…

创客匠人老蒋:创始人IP如何为传统产业注入新活力?

我是老蒋&#xff0c;创客匠人创始人。在当下的商业浪潮中&#xff0c;传统产业究竟该如何突破发展瓶颈&#xff1f;又怎样在IP时代开拓出全新的增长路径&#xff1f;这无疑是众多企业正深陷其中、苦苦思索的难题。这次全球创始人IP领袖高峰论坛上&#xff0c;我们邀请了大三湘…

利用Java爬虫按图搜索1688商品(拍立淘)的实践指南

在当今数字化时代&#xff0c;网购已成为人们生活中不可或缺的一部分。而1688作为国内领先的B2B电商平台&#xff0c;汇聚了海量的商品资源。然而&#xff0c;在面对众多商品时&#xff0c;传统的文字搜索方式有时难以满足我们的需求。比如&#xff0c;当我们看到一件心仪的商品…

Linux 下配置 Golang 环境

go sdk 下载环境&#xff1a;https://golang.google.cn/dl/选择对应的版本&#xff1a; 使用 wget 直接拉包下载到服务器中 wget https://golang.google.cn/dl/go1.23.4.linux-amd64.tar.gz如果找不到 wget 命令&#xff0c;yum 下载 wget yum -y install wget配置 go 的环境…

NVIDIA PyTorch Docker 镜像安装

nvcr.io/nvidia/pytorch:24.12-py3-igpu 是一个 NVIDIA 提供的 PyTorch Docker 镜像&#xff0c;其中包含了 PyTorch 以及与 NVIDIA GPU 相关的库&#xff0c;24.12 表示这个镜像的版本号&#xff0c; py3 表示python3版本&#xff0c;igpu表示集显。 步骤&#xff1a; 确保你…

gesp(C++五级)(4)洛谷:B3872:[GESP202309 五级] 巧夺大奖

gesp(C五级)&#xff08;4&#xff09;洛谷&#xff1a;B3872&#xff1a;[GESP202309 五级] 巧夺大奖 题目描述 小明参加了一个巧夺大奖的游戏节目。主持人宣布了游戏规则&#xff1a; 游戏分为 n n n 个时间段&#xff0c;参加者每个时间段可以选择一个小游戏。 游戏中共有…

迅翼SwiftWing | ROS 固定翼开源仿真平台正式发布!

经过前期内测调试&#xff0c;ROS固定翼开源仿真平台今日正式上线&#xff01;现平台除适配PX4ROS环境外&#xff0c;也已实现APROS环境下的单机飞行控制仿真适配。欢迎大家通过文末链接查看项目地址以及具体使用手册。 1 平台简介 ROS固定翼仿真平台旨在实现固定翼无人机决策…

算法面试准备 - 手撕系列第一期 - Softmax

算法面试准备 - 手撕系列第一期 - Softmax 目录 算法面试准备 - 手撕系列第一期 - SoftmaxSoftmax原理图Softmax实现代码 - 复杂版和简单版本(推荐简单版本)参考 Softmax原理图 Softmax原理图 Softmax实现代码 - 复杂版和简单版本(推荐简单版本) 方法一&#xff1a;循环计算 …