Java装饰器案例如何拓展功能

wen java案例 28

本文目录导读:

Java装饰器案例如何拓展功能

  1. 装饰器模式核心思想
  2. 基础案例:咖啡点单系统
  3. 使用示例
  4. 更复杂的功能拓展
  5. 进阶:使用接口+泛型
  6. 实际应用场景
  7. 注意事项
  8. 最佳实践

装饰器模式核心思想

装饰器模式允许动态地给对象添加额外功能,比继承更灵活,核心是:

  • 不修改原有类结构
  • 通过组合方式扩展功能
  • 支持多层装饰

基础案例:咖啡点单系统

抽象组件接口

// 咖啡组件接口
public interface Coffee {
    String getDescription();
    double cost();
}

具体组件(基础实现)

// 基础咖啡 - 美式咖啡
public class AmericanCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "美式咖啡";
    }
    @Override
    public double cost() {
        return 20.0;
    }
}
// 基础咖啡 - 拿铁
public class Latte implements Coffee {
    @Override
    public String getDescription() {
        return "拿铁";
    }
    @Override
    public double cost() {
        return 25.0;
    }
}

抽象装饰器

// 装饰器抽象类,核心:持有Coffee引用
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
    // 默认委托给被装饰对象
    @Override
    public String getDescription() {
        return coffee.getDescription();
    }
    @Override
    public double cost() {
        return coffee.cost();
    }
}

具体装饰器(功能扩展)

// 加奶装饰器
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 牛奶";
    }
    @Override
    public double cost() {
        return coffee.cost() + 5.0;  // 加奶额外5元
    }
}
// 加糖装饰器
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 糖";
    }
    @Override
    public double cost() {
        return coffee.cost() + 2.0;  // 加糖额外2元
    }
}
// 加奶油装饰器
public class WhipDecorator extends CoffeeDecorator {
    public WhipDecorator(Coffee coffee) {
        super(coffee);
    }
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 奶油";
    }
    @Override
    public double cost() {
        return coffee.cost() + 8.0;  // 加奶油额外8元
    }
}

使用示例

基本使用

public class CoffeeShop {
    public static void main(String[] args) {
        // 基础美式咖啡
        Coffee coffee = new AmericanCoffee();
        System.out.println(coffee.getDescription() + ":¥" + coffee.cost());
        // 输出:美式咖啡:¥20.0
        // 美式 + 牛奶
        Coffee milkCoffee = new MilkDecorator(new AmericanCoffee());
        System.out.println(milkCoffee.getDescription() + ":¥" + milkCoffee.cost());
        // 输出:美式咖啡 + 牛奶:¥25.0
        // 美式 + 牛奶 + 糖
        Coffee sweetMilkCoffee = new SugarDecorator(
            new MilkDecorator(new AmericanCoffee())
        );
        System.out.println(sweetMilkCoffee.getDescription() + ":¥" + sweetMilkCoffee.cost());
        // 输出:美式咖啡 + 牛奶 + 糖:¥27.0
        // 拿铁 + 奶油 + 糖
        Coffee latteWithWhipAndSugar = new SugarDecorator(
            new WhipDecorator(new Latte())
        );
        System.out.println(latteWithWhipAndSugar.getDescription() + ":¥" + latteWithWhipAndSugar.cost());
        // 输出:拿铁 + 奶油 + 糖:¥35.0
    }
}

动态组合

// 可以根据用户选择动态组合
public Coffee createCustomCoffee(String base, List<String> addons) {
    Coffee coffee;
    // 选择基底
    switch (base) {
        case "美式":
            coffee = new AmericanCoffee();
            break;
        case "拿铁":
            coffee = new Latte();
            break;
        default:
            throw new IllegalArgumentException("未知咖啡类型");
    }
    // 动态添加配料
    for (String addon : addons) {
        switch (addon) {
            case "牛奶":
                coffee = new MilkDecorator(coffee);
                break;
            case "糖":
                coffee = new SugarDecorator(coffee);
                break;
            case "奶油":
                coffee = new WhipDecorator(coffee);
                break;
        }
    }
    return coffee;
}

更复杂的功能拓展

添加新功能:杯子大小

// 杯子大小装饰器
public class SizeDecorator extends CoffeeDecorator {
    private String size;
    public SizeDecorator(Coffee coffee, String size) {
        super(coffee);
        this.size = size;
    }
    @Override
    public String getDescription() {
        return size + "杯 " + coffee.getDescription();
    }
    @Override
    public double cost() {
        double baseCost = coffee.cost();
        switch (size) {
            case "大":
                return baseCost + 5.0;
            case "中":
                return baseCost + 3.0;
            default: // 小
                return baseCost;
        }
    }
}
// 使用
Coffee largeMilkCoffee = new SizeDecorator(
    new MilkDecorator(new AmericanCoffee()), "大"
);
System.out.println(largeMilkCoffee.getDescription() + ":¥" + largeMilkCoffee.cost());
// 输出:大杯 美式咖啡 + 牛奶:¥30.0

添加新功能:温度控制

public class TemperatureDecorator extends CoffeeDecorator {
    private String temperature;
    public TemperatureDecorator(Coffee coffee, String temperature) {
        super(coffee);
        this.temperature = temperature;
    }
    @Override
    public String getDescription() {
        return coffee.getDescription() + "(" + temperature + ")";
    }
    @Override
    public double cost() {
        // 冰咖啡额外收费
        if ("冰".equals(temperature)) {
            return coffee.cost() + 2.0;
        }
        return coffee.cost();
    }
}
// 多层装饰示例
Coffee customCoffee = new TemperatureDecorator(
    new SizeDecorator(
        new SugarDecorator(
            new WhipDecorator(new Latte())
        ), "中"
    ), "冰"
);
System.out.println(customCoffee.getDescription() + ":¥" + customCoffee.cost());
// 输出:中杯 拿铁 + 奶油 + 糖(冰):¥40.0

进阶:使用接口+泛型

// 更通用的装饰器接口
public interface Decorator<T> {
    T decorate(T target);
}
// 具体装饰器可以更灵活
public class LoggingDecorator<T> implements Decorator<T> {
    @Override
    public T decorate(T target) {
        // 可以为任何对象添加日志功能
        System.out.println("调用对象:" + target.getClass().getSimpleName());
        return target;
    }
}

实际应用场景

  1. Java I/O流BufferedInputStream装饰FileInputStream
  2. Spring框架@Transactional@Cacheable等注解
  3. Servlet Filter:多个Filter链式处理请求
  4. 日志框架:不同Appender、Layout的组合

注意事项

优点

  • ✅ 比继承更灵活
  • ✅ 遵循开闭原则
  • ✅ 功能可以动态组合
  • ✅ 避免类爆炸

缺点

  • ❌ 会产生很多小类
  • ❌ 多层装饰时调试复杂
  • ❌ 装饰顺序可能影响结果

最佳实践

  1. 明确边界:装饰器应只添加功能,不改变核心逻辑
  2. 保持简单:避免超过3-4层装饰
  3. 工厂方法:结合工厂模式简化创建过程
  4. 文档清晰:记录装饰器的执行顺序

通过装饰器模式,您可以像搭积木一样灵活组合功能,既保持了代码的整洁,又提供了无限扩展的可能性。

抱歉,评论功能暂时关闭!