装饰者模式

简介

定义: 动态地给一个对象添加一些额外的职责。例如:当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

使用场景:

  • Java I/O流(InputStream, OutputStream)

  • Servlet API(Wrapper)

  • 咖啡店点单系统

实现要点:

  • 装饰器持有被装饰对象

  • 装饰器实现相同接口

  • 可以多层装饰

UML

代码示例

  1. 基础咖啡接口

public interface Coffee {
    
    /**
     * 获取咖啡描述
     */
    String getDescription();
    
    /**
     * 获取咖啡价格
     */
    double getCost();
    
    /**
     * 获取咖啡详细信息
     */
    default String getDetails() {
        return String.format("%s - ¥%.2f", getDescription(), getCost());
    }
}
  1. 具体的咖啡

public class Americano implements Coffee {

    @Override
    public String getDescription() {
        return "美式咖啡";
    }

    @Override
    public double getCost() {
        return 12.0;
    }
}
public class Cappuccino implements Coffee {

    @Override
    public String getDescription() {
        return "卡布奇诺";
    }

    @Override
    public double getCost() {
        return 20.0;
    }
}
public class Espresso implements Coffee {

    @Override
    public String getDescription() {
        return "浓缩咖啡";
    }

    @Override
    public double getCost() {
        return 15.0;
    }
}
  1. 咖啡装饰者抽象器

public abstract class CoffeeDecorator implements Coffee {
    
    protected Coffee coffee;
    
    /**
     * 构造函数
     * @param coffee 被装饰的咖啡对象
     */
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
    
    /**
     * 获取描述 - 由子类实现具体的装饰逻辑
     */
    @Override
    public abstract String getDescription();
    
    /**
     * 获取价格 - 由子类实现具体的价格计算
     */
    @Override
    public abstract double getCost();
}
  1. 咖啡具体装饰

public class CaramelDecorator extends CoffeeDecorator {
    
    public CaramelDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 焦糖";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 5.0;
    }
}
public class MilkDecorator extends CoffeeDecorator {
    
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 牛奶";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 3.0;
    }
}
public class VanillaDecorator extends CoffeeDecorator {
    
    public VanillaDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 香草";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 4.0;
    }
}
  1. 使用方式

public class Test {

    public static void main(String[] args) {
        System.out.println("=== 装饰模式 - 咖啡店示例 ===\n");

        // 测试1: 基础咖啡
        System.out.println("--- 测试基础咖啡 ---");
        Coffee espresso = new Espresso();
        printCoffee(espresso);

        Coffee americano = new Americano();
        printCoffee(americano);

        Coffee cappuccino = new Cappuccino();
        printCoffee(cappuccino);

        System.out.println("\n--- 测试单个装饰器 ---");
        // 测试2: 单个装饰器
        Coffee espressoWithMilk = new MilkDecorator(new Espresso());
        printCoffee(espressoWithMilk);


        System.out.println("\n--- 测试多个装饰器组合 ---");
        // 测试3: 多个装饰器组合
        Coffee complexCoffee1 = new CaramelDecorator(
                new VanillaDecorator(
                        new MilkDecorator(
                                new Espresso()
                        )
                )
        );
        printCoffee(complexCoffee1);

        System.out.println("\n--- 测试不同组合 ---");
        // 测试4: 不同的装饰器组合

        Coffee premiumCappuccino = new CaramelDecorator(
                new MilkDecorator(
                        new Cappuccino()
                )
        );
        printCoffee(premiumCappuccino);

        System.out.println("\n--- 测试装饰器的动态性 ---");
        // 测试5: 动态添加装饰器
        Coffee baseCoffee = new Espresso();
        System.out.println("初始咖啡: " + baseCoffee.getDetails());

        baseCoffee = new MilkDecorator(baseCoffee);
        System.out.println("添加牛奶: " + baseCoffee.getDetails());

        baseCoffee = new VanillaDecorator(baseCoffee);
        System.out.println("添加香草: " + baseCoffee.getDetails());

        System.out.println("\n=== 装饰模式说明 ===");
        System.out.println("1. 组件接口: Coffee - 定义咖啡的基本操作");
        System.out.println("2. 具体组件: Espresso, Americano等 - 基础咖啡类型");
        System.out.println("3. 装饰器抽象类: CoffeeDecorator - 持有组件引用");
        System.out.println("4. 具体装饰器: MilkDecorator等 - 添加具体功能");
        System.out.println("5. 客户端: 可以动态组合装饰器");

        System.out.println("\n=== 装饰模式优势 ===");
        System.out.println("✅ 动态扩展: 可以在运行时动态添加功能");
        System.out.println("✅ 组合灵活: 可以任意组合多个装饰器");
        System.out.println("✅ 职责单一: 每个装饰器只负责一个功能");
        System.out.println("✅ 符合开闭原则: 对扩展开放,对修改关闭");
        System.out.println("✅ 避免继承爆炸: 不需要为每种组合创建子类");

        System.out.println("\n=== 装饰模式应用场景 ===");
        System.out.println("📌 Java I/O流: InputStream, OutputStream等");
        System.out.println("📌 Servlet API: HttpServletRequestWrapper等");
        System.out.println("📌 GUI组件: 窗口、按钮的装饰");
        System.out.println("📌 缓存系统: 多层缓存装饰");
        System.out.println("📌 权限控制: 多层权限装饰");
    }

    /**
     * 打印咖啡信息
     */
    private static void printCoffee(Coffee coffee) {
        System.out.println("☕ " + coffee.getDetails());
    }
}

Last updated

Was this helpful?