装饰器模式(Decorator Pattern)

在Java中,装饰器模式(Decorator Pattern)是一种结构型设计模式,允许在不修改原始对象的情况下,动态地为其添加新功能。以下从原理、结构、实现方式到实际应用场景进行详细说明:

一、装饰器模式的核心原理

装饰器模式通过包装原有对象,在保持其接口不变的基础上,动态添加额外功能。相比继承,它更灵活,避免了类数量膨胀问题125。

核心特点

  1. 动态扩展:运行时组合功能,而非通过静态继承。
  2. 透明性:装饰后的对象与原始对象接口一致,可无缝替换。
  3. 组合优于继承:遵循开闭原则,灵活扩展功能25。

二、装饰器模式的结构

装饰器模式包含以下角色:

  1. Component(抽象组件):定义核心接口,所有具体组件和装饰器需实现该接口。
  2. ConcreteComponent(具体组件):实现Component接口的原始对象,如基础咖啡类。
  3. Decorator(抽象装饰器):持有Component对象的引用,并实现相同接口,用于定义通用装饰逻辑。
  4. ConcreteDecorator(具体装饰器):继承自Decorator,负责添加特定功能(如加牛奶、加糖)25。

三、实现步骤与代码示例

以咖啡订单系统为例,展示标准实现:

1. 定义抽象组件(Component)

public interface Coffee {
    double getCost();              // 获取价格
    String getDescription();      // 获取描述
}

2. 创建具体组件(ConcreteComponent)

public class SimpleCoffee implements Coffee {
    @Override
    public double getCost() {
        return 10; // 基础咖啡价格
    }
    
    @Override
    public String getDescription() {
        return "简单咖啡";
    }
}

3. 定义抽象装饰器(Decorator)

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee; // 被装饰的咖啡对象
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
    
    @Override
    public double getCost() {
        return decoratedCoffee.getCost();
    }
    
    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }
}

4. 实现具体装饰器(ConcreteDecorator)

public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public double getCost() {
        return super.getCost() + 5; // 加牛奶附加费用
    }
    
    @Override
    public String getDescription() {
        return super.getDescription() + ", 牛奶";
    }
}

public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public double getCost() {
        return super.getCost() + 2; // 加糖附加费用
    }
    
    @Override
    public String getDescription() {
        return super.getDescription() + ", 糖";
    }
}

5. 客户端组合使用

public class CoffeeShop {
    public static void main(String[] args) {
        // 基础咖啡
        Coffee coffee = new SimpleCoffee();
        
        // 动态添加牛奶和糖
        coffee = new MilkDecorator(coffee);
        coffee = new SugarDecorator(coffee);
        
        System.out.println("总价: " + coffee.getCost());          // 输出: 17
        System.out.println("描述: " + coffee.getDescription());  // 输出: 简单咖啡, 牛奶, 糖
    }
}

四、其他实现方式

1. 内部类实现

适用于装饰器仅针对特定组件的场景:

public class Component {
    public void operation() {
        System.out.println("基础操作");
    }
    
    public class Decorator extends Component {
        @Override
        public void operation() {
            super.operation(); // 调用原始操作
            System.out.println("附加功能");
        }
    }
}
// 使用
Component component = new Component();
Component decorated = component.new Decorator();
decorated.operation(); // 输出:基础操作 + 附加功能

2. Java 8函数式接口实现

利用Lambda简化装饰逻辑:

@FunctionalInterface
interface ComponentOperation {
    void execute();
}

public class ConcreteComponent implements ComponentOperation {
    public void execute() {
        System.out.println("执行基础操作");
    }
}

public class Decorator implements ComponentOperation {
    private final ComponentOperation componentOperation;
    private final Runnable additionalBehavior;
    
    public Decorator(ComponentOperation componentOperation, Runnable additionalBehavior) {
        this.componentOperation = componentOperation;
        this.additionalBehavior = additionalBehavior;
    }
    
    public void execute() {
        componentOperation.execute();
        additionalBehavior.run();
    }
}

// 使用
ComponentOperation base = new ConcreteComponent();
ComponentOperation decorated = new Decorator(base, () -> System.out.println("日志记录"));
decorated.execute(); // 输出:执行基础操作 + 日志记录

五、优缺点与适用场景

优点

  1. 灵活扩展:通过组合多个装饰器实现不同功能(如咖啡+牛奶+糖)。
  2. 避免类爆炸:无需为每个功能组合创建子类。
  3. 符合开闭原则:新增功能只需添加装饰器,无需修改现有代码25。

缺点

  1. 性能开销:多层装饰可能增加对象创建和方法调用成本。
  2. 复杂性:装饰链过长时可能导致调试困难25。

适用场景

  1. 动态功能组合:如图形绘制中动态添加形状、颜色等属性。
  2. 透明扩展:在不修改源代码的情况下增强功能(如Java IO流装饰)。
  3. 替代继承:当需要扩展的功能不宜通过继承实现时34。

六、实际应用案例

  1. Java IO流FileInputStreamBufferedInputStreamDataInputStream等装饰,逐层添加缓冲、解析功能。
  2. Spring框架:通过装饰器拦截方法调用,实现事务管理、日志记录等横切关注点4。
  3. 日志系统:动态添加日志级别、格式化等功能2。

总结

装饰器模式通过“包装”实现功能扩展,是替代继承的理想选择。掌握其核心结构(Component、Decorator)和实现方式(接口、抽象类、内部类),能在复杂场景中灵活应用,同时需注意避免过度装饰导致系统复杂度上升

posted @ 2025-06-25 15:34  RyanAce1988  阅读(51)  评论(0)    收藏  举报