装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变对象结构的前提下,动态地给对象添加一些额外的职责或行为。这种模式创建了一个包装对象,也就是装饰器,来包裹真实的对象,并在保持接口一致性的同时,为对象添加新的功能。下面结合具体场景来详细描述装饰模式。
场景描述
假设我们经营一家咖啡店,提供多种咖啡饮品,如浓缩咖啡(Espresso)、美式咖啡(Americano)等。顾客在点单时,可以根据自己的口味选择添加不同的配料,如牛奶(Milk)、糖(Sugar)、巧克力酱(Chocolate Sauce)等。每种配料都会改变咖啡的口感和外观,但咖啡的本质(即基础咖啡)并没有改变。
装饰模式的应用
在这个场景中,我们可以使用装饰模式来设计咖啡和配料的类结构。
-
抽象组件(Component):定义一个咖啡饮品的接口,这个接口是所有咖啡饮品(包括基础咖啡和装饰后的咖啡)共有的。它定义了一个方法(如
getCost()
和getDescription()
),用于获取咖啡的价格和描述。 -
具体组件(Concrete Component):实现抽象组件接口的具体类,代表基础咖啡饮品,如浓缩咖啡(Espresso)。
-
装饰器(Decorator):也是一个实现了抽象组件接口的类,但它还持有一个抽象组件对象的引用。装饰器类通常包含一些用于添加额外职责的方法,并且会调用所持有的组件对象的相应方法。
-
具体装饰器(Concrete Decorator):继承自装饰器类,为组件对象添加新的行为或功能。在这个场景中,具体装饰器可以是牛奶(MilkDecorator)、糖(SugarDecorator)和巧克力酱(ChocolateSauceDecorator)等。
示例代码结构(伪代码)
interface Coffee {
double getCost();
String getDescription();
}
class Espresso implements Coffee {
@Override
public double getCost() {
return 1.5;
}
@Override
public String getDescription() {
return "Espresso";
}
}
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double getCost() {
return coffee.getCost();
}
@Override
public String getDescription() {
return coffee.getDescription();
}
}
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double getCost() {
return super.getCost() + 0.5;
}
@Override
public String getDescription() {
return super.getDescription() + ", Milk";
}
}
// 类似地,可以定义SugarDecorator和ChocolateSauceDecorator等
// 客户端代码
Coffee espresso = new Espresso();
Coffee espressoWithMilk = new MilkDecorator(espresso);
System.out.println(espressoWithMilk.getDescription()); // 输出: Espresso, Milk
System.out.println(espressoWithMilk.getCost()); // 输出: 2.0
装饰模式的优点
- 动态扩展:可以在运行时动态地给对象添加新的功能,而不需要修改对象的结构。
- 灵活性:可以自由地组合和排列不同的装饰器,以创建出各种定制化的对象。
- 避免类爆炸:通过使用装饰模式,可以避免为了支持各种组合而创建大量的子类,从而简化类结构。
总结
装饰模式在咖啡店咖啡定制的场景中得到了很好的应用,它允许我们在不改变基础咖啡饮品的前提下,通过添加不同的配料来创建出多样化的咖啡饮品,满足了顾客的个性化需求。