装饰器模式(Decorator Pattern)
在Java中,装饰器模式(Decorator Pattern)是一种结构型设计模式,允许在不修改原始对象的情况下,动态地为其添加新功能。以下从原理、结构、实现方式到实际应用场景进行详细说明:
一、装饰器模式的核心原理
装饰器模式通过包装原有对象,在保持其接口不变的基础上,动态添加额外功能。相比继承,它更灵活,避免了类数量膨胀问题125。
核心特点:
- 动态扩展:运行时组合功能,而非通过静态继承。
- 透明性:装饰后的对象与原始对象接口一致,可无缝替换。
- 组合优于继承:遵循开闭原则,灵活扩展功能25。
二、装饰器模式的结构
装饰器模式包含以下角色:
- Component(抽象组件):定义核心接口,所有具体组件和装饰器需实现该接口。
- ConcreteComponent(具体组件):实现Component接口的原始对象,如基础咖啡类。
- Decorator(抽象装饰器):持有Component对象的引用,并实现相同接口,用于定义通用装饰逻辑。
- 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(); // 输出:执行基础操作 + 日志记录
五、优缺点与适用场景
优点:
- 灵活扩展:通过组合多个装饰器实现不同功能(如咖啡+牛奶+糖)。
- 避免类爆炸:无需为每个功能组合创建子类。
- 符合开闭原则:新增功能只需添加装饰器,无需修改现有代码25。
缺点:
- 性能开销:多层装饰可能增加对象创建和方法调用成本。
- 复杂性:装饰链过长时可能导致调试困难25。
适用场景:
- 动态功能组合:如图形绘制中动态添加形状、颜色等属性。
- 透明扩展:在不修改源代码的情况下增强功能(如Java IO流装饰)。
- 替代继承:当需要扩展的功能不宜通过继承实现时34。
六、实际应用案例
- Java IO流:
FileInputStream被BufferedInputStream、DataInputStream等装饰,逐层添加缓冲、解析功能。 - Spring框架:通过装饰器拦截方法调用,实现事务管理、日志记录等横切关注点4。
- 日志系统:动态添加日志级别、格式化等功能2。
总结
装饰器模式通过“包装”实现功能扩展,是替代继承的理想选择。掌握其核心结构(Component、Decorator)和实现方式(接口、抽象类、内部类),能在复杂场景中灵活应用,同时需注意避免过度装饰导致系统复杂度上升

浙公网安备 33010602011771号