~/app/articles/NORMAL

cat article/40.md

装饰器模式 (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. 装饰器模式的结构

角色说明

  1. Component(组件):定义原始对象接口(如Beverage)。
  2. ConcreteComponent(具体组件):实现原始对象(如Coffee)。
  3. Decorator(装饰器):持有组件引用并实现其接口(抽象类)。
  4. 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() + " + 芝士";
    }
}

答案:

  1. Pizza
  2. super

题目3(设计题)

用装饰器模式设计游戏角色装备系统:

  • 组件:Character(基础角色)。
  • 装饰器:WeaponDecorator、ArmorDecorator。
    要求:写出完整代码,支持动态叠加装备效果。
$ comments --list (0)

// not signed in


// no comments yet