定义: 装饰者模式是一种结构型设计模式,它允许动态地给对象添加新的功能,而不会改变其原有的结构。与继承不同,装饰者模式通过组合而不是继承来扩展对象的功能,这样可以有效地避免类爆炸问题(多个子类的冗余)。
在装饰者模式中,通常有以下几个关键角色:
抽象组件:定义对象的接口,可以是接口或抽象类。具体组件和装饰者都实现或继承该组件。
具体组件:实现抽象组件接口的具体类,它是被装饰的对象。
装饰者:实现抽象组件接口的类,内部维护一个抽象组件的引用,用于对被装饰对象进行扩展。
具体装饰者:继承装饰者并扩展其功能,可以为被装饰对象动态添加新功能。
优点
灵活性:通过组合而不是继承来扩展对象的功能,可以在运行时选择不同的装饰者动态组合对象。
遵循开闭原则:装饰者模式允许对功能进行扩展,而无需修改现有的代码。
减少子类的冗余:避免类层次的复杂性和继承的弊端。
缺点
复杂性增加:使用装饰者模式会增加系统中类的数量和对象的层次,增加理解和调试的难度。
难以维护:多个装饰者叠加时,调试可能变得困难,因为可能需要跟踪多个装饰者的行为。
实现示例
假设我们有一个咖啡店系统,每种咖啡有不同的类型(如普通咖啡、加牛奶的咖啡、加糖的咖啡等)。我们想要通过装饰者模式来灵活地添加配料,而不是为每种组合创建不同的类。
1. 定义抽象组件 Beverage
// 抽象组件
public abstract class Beverage {// 每种饮料都有一个描述和一个价格protected String description = "Unknown Beverage";public String getDescription() {return description;}public abstract double cost();
}
2. 定义具体组件 Coffee
// 具体组件 - 咖啡
public class Coffee extends Beverage {public Coffee() {description = "Coffee";}@Overridepublic double cost() {return 5.0; // 基本咖啡的价格}
}
3. 定义装饰者 CondimentDecorator
// 抽象装饰者 - 调料装饰器
public abstract class CondimentDecorator extends Beverage {// 强制要求具体装饰者必须实现 getDescription 方法public abstract String getDescription();
}
4. 定义具体装饰者 Milk
和 Sugar
// 具体装饰者 - 牛奶
public class Milk extends CondimentDecorator {// 被装饰的对象Beverage beverage;public Milk(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Milk";}@Overridepublic double cost() {return 1.5 + beverage.cost(); // 牛奶的价格加上原始饮料的价格}
}// 具体装饰者 - 糖
public class Sugar extends CondimentDecorator {// 被装饰的对象Beverage beverage;public Sugar(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Sugar";}@Overridepublic double cost() {return 0.5 + beverage.cost(); // 糖的价格加上原始饮料的价格}
}
5. 测试装饰者模式
public class CoffeeShop {public static void main(String[] args) {// 创建一杯基本的咖啡Beverage beverage = new Coffee();System.out.println(beverage.getDescription() + " $" + beverage.cost());// 给咖啡加牛奶beverage = new Milk(beverage);System.out.println(beverage.getDescription() + " $" + beverage.cost());// 给咖啡加牛奶和糖beverage = new Sugar(beverage);System.out.println(beverage.getDescription() + " $" + beverage.cost());}
}
输出结果:
Coffee $5.0
Coffee, Milk $6.5
Coffee, Milk, Sugar $7.0