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