目录
一、系统背景
二、UML 类图
抽象组件类(Component):
具体组件类(Concrete Component):
抽象装饰者类(Decorator):
具体装饰者类(Concrete Decorator):
四、代码实现示例
四、动态扩展的优势
五、实际应用场景
六、总结
在软件设计中,设计模式是解决复杂问题的通用方案。今天,我们通过星巴克咖啡下单系统的 UML 类图,来探讨如何使用装饰者模式(Decorator Pattern)来构建一个灵活且可扩展的系统。
一、系统背景
星巴克的咖啡系统需要支持多种饮料和配料的组合,比如:
-
饮料:House Blend(混合咖啡)、Dark Roast(深烘焙咖啡)、Espresso(浓缩咖啡)、Decaf(脱因咖啡)。
-
配料:Milk(牛奶)、Mocha(摩卡)、Soy(豆奶)、Whip(奶油)。
每种饮料和配料都有不同的价格和描述,系统需要动态地计算总价和生成订单描述。
二、UML 类图
采用装饰者模式来实现动态扩展功能:
-
抽象组件类(Component):
-
Beverage
是抽象类,定义了所有饮料的共同接口,包括getDescription()
和cost()
方法。 -
它是所有具体饮料和装饰者的基类。
-
-
具体组件类(Concrete Component):
-
HouseBlend
、DarkRoast
、Espresso
和Decaf
是具体的饮料类,继承自Beverage
。 -
每个类实现了
cost()
方法,返回饮料的基础价格。
-
-
抽象装饰者类(Decorator):
-
CondimentDecorator
是装饰者类,继承自Beverage
。 -
它持有一个
Beverage
对象,通过组合的方式实现动态扩展。
-
-
具体装饰者类(Concrete Decorator):
-
Milk
、Mocha
、Soy
和Whip
是具体的配料类,继承自CondimentDecorator
。 -
每个类实现了
cost()
方法,返回配料的价格,并调用被装饰对象的cost()
方法。
-
四、代码实现示例
以下是装饰者模式的核心代码实现:
// 抽象组件类:Beverage
abstract class Beverage {String description = "未知饮料";public String getDescription() {return description;}public abstract double cost();
}// 具体组件类:HouseBlend
class HouseBlend extends Beverage {public HouseBlend() {description = "家常咖啡";}@Overridepublic double cost() {return 0.89;}
}// 具体组件类:DarkRoast
class DarkRoast extends Beverage {public DarkRoast() {description = "深烘焙咖啡";}@Overridepublic double cost() {return 0.99;}
}// 具体组件类:Espresso
class Espresso extends Beverage {public Espresso() {description = "浓缩咖啡";}@Overridepublic double cost() {return 1.99;}
}// 具体组件类:Decaf
class Decaf extends Beverage {public Decaf() {description = "无咖啡因咖啡";}@Overridepublic double cost() {return 1.05;}
}// 抽象装饰类:CondimentDecorator
abstract class CondimentDecorator extends Beverage {public abstract String getDescription();
}// 具体装饰类:Milk
class Milk extends CondimentDecorator {Beverage beverage;public Milk(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ",牛奶";}@Overridepublic double cost() {return beverage.cost() + 0.10;}
}// 具体装饰类:Mocha
class Mocha extends CondimentDecorator {Beverage beverage;public Mocha(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ",摩卡";}@Overridepublic double cost() {return beverage.cost() + 0.20;}
}// 具体装饰类:Soy
class Soy extends CondimentDecorator {Beverage beverage;public Soy(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ",豆奶";}@Overridepublic double cost() {return beverage.cost() + 0.15;}
}// 具体装饰类:Whip
class Whip extends CondimentDecorator {Beverage beverage;public Whip(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ",奶油";}@Overridepublic double cost() {return beverage.cost() + 0.10;}
}// 测试类
class StarbucksTest {public static void main(String[] args) {Beverage beverage = new Espresso();System.out.println(beverage.getDescription() + " 价格: $" + beverage.cost());beverage = new DarkRoast();beverage = new Milk(beverage);beverage = new Mocha(beverage);System.out.println(beverage.getDescription() + " 价格: $" + beverage.cost());beverage = new HouseBlend();beverage = new Soy(beverage);beverage = new Whip(beverage);System.out.println(beverage.getDescription() + " 价格: $" + beverage.cost());}
}
四、动态扩展的优势
装饰者模式的主要优点在于:
-
动态扩展:可以在运行时动态地添加功能,而无需修改现有代码。
-
灵活性:可以组合多个装饰者,实现复杂的功能。
-
避免类爆炸:如果使用继承来实现所有组合,类的数量会呈指数增长,而装饰者模式避免了这一问题。
五、实际应用场景
假设用户点了一杯深烘焙咖啡(Dark Roast),并添加了牛奶(Milk)和奶油(Whip),代码如下:
Beverage beverage = new DarkRoast();
beverage = new Milk(beverage);
beverage = new Whip(beverage);System.out.println(beverage.getDescription() + " $" + beverage.cost());
输出:
Dark Roast, Milk, Whip $1.49
通过装饰者模式,系统可以轻松支持复杂的订单组合,而无需修改现有代码。
六、总结
装饰者模式是解决动态扩展问题的优雅方案。通过 UML 类图,我们可以清晰地看到系统的设计结构,以及如何通过组合实现功能的扩展。在星巴克咖啡系统中,装饰者模式不仅提高了代码的可维护性,还为未来的扩展提供了极大的便利。
希望这篇博客能帮助你更好地理解UML类图和装饰者模式及其在实际项目中的应用!