装饰器模式 (Decorator) 全面讲解
学习笔记
设计模式
面向对象
Java
软件设计
装饰器模式
代码设计
本文全面讲解了装饰器模式,包括其定义、核心思想、适用场景、结构以及一个示例代码。装饰器模式是一种结构型设计模式,用于动态地为对象添加额外职责,而无需修改其原始类。
date: 2025-06-22T20:34:00 tags:
- 复习
- 面向对象
- 设计模式
- Java
装饰器模式 (Decorator) 全面讲解
1. 什么是装饰器模式?
装饰器模式是结构型设计模式,用于动态地为对象添加额外职责,而无需修改其原始类。
- 核心思想:通过组合代替继承,灵活扩展对象功能。
- 类比:
- 给咖啡加糖、加奶(不改变咖啡本身,动态添加配料)。
- 游戏装备系统(武器+宝石装饰)。
🔹 适用场景
- 需要动态扩展对象功能(如Java I/O流、GUI组件)。
- 不适合使用继承的情况(如子类爆炸)。
2. 为什么需要装饰器模式?
问题场景(继承的缺陷)
假设有一个Beverage(饮料)类,需要支持多种配料组合:
// 传统继承方式:类爆炸!
class CoffeeWithSugar extends Coffee { /*...*/ }
class CoffeeWithMilk extends Coffee { /*...*/ }
class CoffeeWithSugarAndMilk extends Coffee { /*...*/ }
// 每新增一种配料,子类数量指数增长!
解决方案
用装饰器动态组合功能,避免继承的僵化。
3. 装饰器模式的结构
角色说明
Component(组件):定义原始对象接口(如Beverage)。ConcreteComponent(具体组件):实现原始对象(如Coffee)。Decorator(装饰器):持有组件引用并实现其接口(抽象类)。ConcreteDecorator(具体装饰器):添加具体功能(如SugarDecorator)。
4. 示例代码(咖啡加料系统)
步骤1:定义组件接口
// 组件接口
interface Beverage {
String getDescription();
double cost();
}
步骤2:实现具体组件
// 具体组件:咖啡
class Coffee implements Beverage {
@Override
public String getDescription() {
return "咖啡";
}
@Override
public double cost() {
return 10.0;
}
}
步骤3:定义装饰器基类
// 装饰器基类(关键:实现组件接口并持有组件引用)
abstract class CondimentDecorator implements Beverage {
protected Beverage beverage; // 被装饰的对象
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
}
步骤4:实现具体装饰器
// 具体装饰器:糖
class SugarDecorator extends CondimentDecorator {
public SugarDecorator(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + " + 糖";
}
@Override
public double cost() {
return beverage.cost() + 2.0;
}
}
// 具体装饰器:牛奶
class MilkDecorator extends CondimentDecorator {
public MilkDecorator(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + " + 牛奶";
}
@Override
public double cost() {
return beverage.cost() + 3.0;
}
}
步骤5:客户端调用
public class Client {
public static void main(String[] args) {
// 原始咖啡
Beverage coffee = new Coffee();
System.out.println(coffee.getDescription() + " 价格: " + coffee.cost());
// 动态添加装饰
Beverage coffeeWithSugar = new SugarDecorator(coffee);
Beverage coffeeWithMilkAndSugar = new MilkDecorator(coffeeWithSugar);
System.out.println(coffeeWithMilkAndSugar.getDescription() +
" 价格: " + coffeeWithMilkAndSugar.cost());
}
}
输出:
咖啡 价格: 10.0
咖啡 + 糖 + 牛奶 价格: 15.0
5. 关键点总结
🔹 装饰器 vs 继承
| 对比项 | 继承 | 装饰器模式 |
|---|---|---|
| 扩展方式 | 静态(编译时) | 动态(运行时) |
| 灵活性 | 低(需预先定义子类) | 高(可任意组合装饰) |
🔹 优点
- 符合开闭原则:无需修改原有代码即可扩展功能。
- 避免类爆炸:通过组合实现多层次装饰。
🔹 缺点
- 增加系统复杂度(需设计多层装饰器)。
6. 互动实践
问题1:以下代码是装饰器模式吗?为什么?
class Coffee {
private boolean hasSugar;
private boolean hasMilk;
void addSugar() { hasSugar = true; }
void addMilk() { hasMilk = true; }
}
答案:不是!这是通过字段控制功能,装饰器模式应通过对象组合实现。
问题2:如何用装饰器模式设计文本编辑器?
任务:
- 组件:
Text(基础文本)。 - 装饰器:
BoldDecorator(加粗)、ItalicDecorator(斜体)。 - 补全代码:
interface TextComponent { /*...*/ }
class BoldDecorator implements TextComponent { /*...*/ }
7. 考试练习题
题目1(概念题)
装饰器模式的核心是?
A. 通过继承扩展功能
B. 通过组合动态添加职责
C. 隐藏对象创建细节
D. 优化算法性能
答案:B
题目2(代码填空)
补全装饰器模式的代码:
abstract class PizzaDecorator implements Pizza {
protected ____ pizza; // 填空1
public PizzaDecorator(Pizza pizza) {
this.pizza = pizza;
}
}
class CheeseDecorator extends PizzaDecorator {
public CheeseDecorator(Pizza pizza) {
____(pizza); // 填空2
}
@Override
public String getDescription() {
return pizza.getDescription() + " + 芝士";
}
}
答案:
Pizzasuper
题目3(设计题)
用装饰器模式设计游戏角色装备系统:
- 组件:
Character(基础角色)。 - 装饰器:
WeaponDecorator、ArmorDecorator。
要求:写出完整代码,支持动态叠加装备效果。