目录
- 一、装饰器模式概述
- 二、装饰器模式的实现步骤
- 1.故事背景:机器人功能扩展的两种方案
- ⑴.方案一:传统继承(厂家升级方案)
- ⑵.方案二:装饰器模式
- 三、流程图和内存图
- 1.创建基础机器人
- 2.第一次装饰:添加拖地功能
- 3.调用原始功能
- 4.调用新增功能
- 5.第二次装饰:添加跳舞功能
- 6.调用原始功能(多层装饰后)
- 7.调用第一层装饰器功能
- 8.调用第二层装饰器功能
- 四、实战中的装饰器模式
- 1. Java I/O 库中的应用
- 2. Spring 框架中的应用
在 Java 的www.devze.com世界里,设计模式是开发者手中的利器,它们帮助我们以更优雅、更灵活的方式构建软件系统。今天,我们就来深入探讨其中一种非常实用的设计模式 —— 装饰器模式(Decorator Pattern)。
一、装饰器模式概述
装饰器模式属于结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这就好比给一个普通的杯子加上杯盖、杯套,让它具备保温、防烫等功能,而杯子本身的基本结构并没有发生变化。在软件开发中,当我们需要在运行时动态地为对象添加职责,并且避免通过继承来扩展功能带来的类层次结构复杂问题时,装饰器模式就派上用场了。
装饰器模式主要包含以下几个角色:
- 抽象组件(Component):定义一个抽象接口,规范具体组件和装饰器的行为。
- 具体组件(Concrete Component):实现抽象组件接口,是被装饰的具体对象。
- 抽象装饰器(Decorator):继承或实现抽象组件接口,持有一个抽象组件的引用,并定义一个可以动态添加职责的方法。
- 具体装饰器(Concrete Decorator):实现抽象装饰器接口,负责为具体组件添加具体的功能。
二、装饰器模式的实现步骤
1.故事背景:机器人功能扩展的两种方案
在智能家居领域,某科技公司推出了第一代家用机器人,它具备三个核编程心功能:对话、唱歌和播放音乐。
// 第一代机器人:基础功能 interface Robot { void talk(); // 对话 void sing(); // 唱歌 void playMusic(); // 播放音乐 } class FirstGenerationRobot implements Robot { @Override public void talk() { System.out.println("机器人:你好,我能陪你聊天"); } @Override public void sing() { System.out.println("机器人:正在播放《青花瓷》"); } @Override public void playMusic() { System.out.println("机器人:正在播放轻音乐"); } }
随着用户需求升级,厂家希望扩展机器人的功能,让它能够扫地和跳舞。针对这个需求,有两种技术方案可供选择:
⑴.方案一:传统继承(厂家升级方案)
厂家选择开发第二代机器人,通过继承第一代产品并添加新功能:
接口定义
// 基础接口:第一代机器人支持的功能 interface Robot { void talk(); void sing(); void playMusic(); }
类实现
// 第一代机器人(基础实现) class FirstGenerationRobot implements Robot { @Override public void talk() { System.out.println("对话中..."); } @Override public void sing() { System.out.println("正在唱歌..."); } @Override public void playMusic() { System.out.println("播放音乐中..."); } } // 第二代机器人:通过继承方式扩展功能 class SecondGenerationRobot extends FirstGenerationRobot { public void sweep() { System.out.println("正在扫地..."); } public void dance() { System.out.println("正在跳舞..."); } }
测试代码
public class InheritanceTest { public static void main(String[] args) { System.out.println("=== 继承方式测试 ==="); SecondGenerationRobot robot = new SecondGenerationRobot(); robot.talk(); robot.sing(); rhttp://www.devze.comobot.playMusic(); robot.sweep(); // 扩展功能 robot.dance(); // 扩展功能 } }
⑵.方案二:装饰器模式
通过组合方式动态添加新功能:
以下是根据机器人例子实现的装饰器模式代码及详细解释:
抽象组件(Robot 接口)
interface Robot { void talk(); // 对话 void sing(); // 唱歌 void playMusic(); // 放音乐 }
- 作用:定义机器人的基本功能,作为装饰器模式的核心接口,规范所有机器人(包括原始机器人和装饰后的机器人)的行为。
具体组件(第一代机器人)
class FirstGenerationRobot implements Robot { @Override public void talk() { System.out.println("第一代机器人:对话"); } @Override public void sing() { System.out.println("第一代机器人:唱歌"); } @Override public void playMusic() { System.out.println("第一代机器人:放音乐"); } }
- 作用:实现抽象组件,是被装饰的原始对象(第一代机器人,具有基本功能)。
抽象装饰器(RobotDecorator)
abstract class RobotDecorator implements Robot { protected Robot robot; // 持有被装饰的机器人对象 public RobotDecorator(Robot robot) { this.robot = robot; } // 转发原始功能(保持原有功能不变) @Override public void talk() { robot.talk(); } @Override public void sing() { robot.sing(); } @Override public void playMusic() { robot.playMusic(); } }
- 作用:作为装饰器的基类,继承抽象组件接口,通过组合(关联)持有原始机器人对象。它实现了原始功能的转发,确保装饰时不破坏原有功能,同时为具体装饰器提供统一的扩展框架。
具体装饰器(添加拖地和跳舞功能)
Java 中的 super 关键字
// 拖地装饰器:继承自RobotDecorator,用于为机器人添加拖地功能 class SweepFloorDecorator extends RobotDecorator { // 构造函数:接收被装饰的机器人实例 public SweepFloorDecorator(Robot robot) { http://www.devze.com // 通过super调用父类构造函数,保存对原始机器人的引用 super(robot); } public void sweepFloor() { // 新增功能:拖地 System.out.println("装饰后:拖地"); } } // 跳舞装饰器 class DanceDecorator extends RobotDecorator { public DanceDecorator(Robot robot) { super(robot); } public void dance() { // 新增功能:跳舞 System.out.println("装饰后:跳舞"); } }
测试代码
public class RobotDemo { public static void main(String[] args) { // 原始机器人(第一代) Robot robot = new FirstGenerationRobot(); robot.talk(); // 原始功能:对话 robot.sing(); // 原始功能:唱歌 robot.playMusic(); // 原始功能:放音乐 // 装饰器扩展:添加拖地功能 SweepFloorDecorator decoratedwithSweep = new SweepFloorDecorator(robot); decoratedWithSweep.talk(); // 保留原始功能 decoratedWithSweep.sweepFloor(); // 新增功能:拖地 // 再装饰:添加跳舞功能 DanceDecorator fullyDecorated = new DanceDecorator(decoratedWithSweep); fullyDecorated.talk(); // 保留原始功能 // 正确调用拖地功能 decoratedWithSweep.sweepFloor(); // 拖地功能 // 新增功能:跳舞 fullyDecorated.dance(); } }
装饰器模式通过组合而非继承,实现了运行时动态扩展对象功能,避免了继承带来的类爆炸问题,是处理 “对象功能扩展” 的优雅方案。在机器人例子中,利用装饰器模式,无需等待厂家更新(继承方式),即可快速为第一代机器人添加拖地、跳舞功能,体现了模式的灵活性和实用性。
- 继承机制适合功能较为稳定、扩展需求明确的场景,实现简单,但不够灵活。
- 装饰器模式适合需要动态组合功能、避免类爆炸的情况,虽然实现略复杂,但更符合开闭原则(对扩展开放,对修改关闭)。
三、流程图和内存图
1.创建基础机器人
Robot robot = new FirstGenerationRobot();
- 创建第一代机器人实例,具备基础功能(talk/sing/playMusipythonc)
2.第一次装饰:添加拖地功能
SweepFloorDecorator decoratedWithSweep = new SweepFloorDecorator(robot);
SweepFloorDecorator
持有对原始机器人的引用- 继承了
RobotDecorator
的默认实现(转发所有方法调用)
3.调用原始功能
decoratedWithSweep.talk();
- 执行流程:
decoratedWithSweep.talk()
调用RobotDecorator
的实现RobotDecorator
转发给被装饰对象:robot.talk()
- 最终执行
FirstGenerationRobot.talk()
4.调用新增功能
decoratedWithSweep.sweepFloor();
- 直接调用
SweepFloorDecorator
新增的方法 - 输出:"装饰后:拖地"
5.第二次装饰:添加跳舞功能
DanceDecorator fullyDecorated = new DanceDecorator(decoratedWithSweep);
DanceDecorator
持有对SweepFloorDecorator
的引用- 形成装饰器嵌套结构:
DanceDecorator -> SweepFloorDecorator -> FirstGenerationRobot
6.调用原始功能(多层装饰后)
fullyDecorated.talk();
- 执行流程:
fullyDecorated.talk()
调用RobotDecorator
的实现- 转发给被装饰对象:
decoratedWithSweep.talk()
decoratedWithSweep.talk()
再次转发:robot.talk()
- 最终执行
FirstGenerationRobot.talk()
7.调用第一层装饰器功能
decoratedWithSweep.sweepFloor();
- 必须通过
decoratedWithSweep
引用调用 - 因为
fullyDecorated
类型是DanceDecorator
,没有直接暴露sweepFloor()
方法
8.调用第二层装饰器功能
fullyDecorated.dance();
- 直接调用
DanceDecorator
新增的方法 - 输出:"装饰后:跳舞"
3 个
Robot
引用的指向对象
变量
robot
- 类型:
Robot
- 指向:
FirstGenerationRobot
实例(原始机器人)
SweepFloorDecorator
内部的robot
成员变量
- 类型:
Robot
(父类RobotDecorator
的protected Robot robot
)- 指向:
FirstGenerationRobot
实例(与变量robot
指向同一个对象)
DanceDecorator
内部的robot
成员变量
- 类型:
Robot
(父类RobotDecorator
的protected Robot robot
)- 指向:
SweepFloorDecorator
实例(与前两个引用指向不同对象)
引用的内存地址比较
Robot robot = new FirstGenerationRobot(); SweepFloorDecorator decoratedWithSweep = new SweepFloorDecorator(robot); DanceDecorator fullyDecorated = new DanceDecorator(decoratedWithSweep); // 内存地址比较(假设对象内存地址为示例值) robot: 0x1000 // 指向 FirstGenerationRobot decoratedWithSweep.robot: 0x1000 // 指向 FirstGenerationRobot(与 robot 相同) fullyDecorated.robot: 0x2000 // 指向 SweepFloorDecorator(与前两者不同)
robot
和decoratedWithSweep.robot
指向相同对象(内存地址均为0x1000
)。fullyDecorated.robot
指向不同对象(内存地址0x2000
,即SweepFloorDecorator
实例)。
四、实战中的装饰器模式
1. Java I/O 库中的应用
// 输入流装饰示例: InputStream fileInput = new FileInputStream("data.txt"); InputStream bufferInput = new BufferedInputStream(fileInput); DataInputStream dataInput = new DataInputStream(bufferInput); // 功能动态组合: // 基础功能:FileInputStream // 装饰1:添加缓冲功能 BufferedInputStream // 装饰2:添加数据处理功能 DataInputStream
2. Spring 框架中的应用
// Spring Security的认证过滤器链: FilterChain filterChain = new UsernamePasswordAuthenticationFilter( new BasicAuthenticationFilter( new SecurityContextPersistenceFilter() ) ); // 每个过滤器都是一个装饰器,动态增强请求处理能力
到此这篇关于Java 装饰器模式Decorator详解及实现步骤的文章就介绍到这了,更多相关Java 装饰器模式Decorator内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论