本文目录导读:

我将为您提供一个完整的Java装饰者模式案例,以咖啡店点餐系统为例来演示。
基本结构
// 1. 抽象组件(Component)- 饮料接口
public interface Beverage {
String getDescription();
double cost();
}
// 2. 具体组件(ConcreteComponent)- 具体的饮料
public class Espresso implements Beverage {
@Override
public String getDescription() {
return "浓缩咖啡";
}
@Override
public double cost() {
return 15.0;
}
}
public class HouseBlend implements Beverage {
@Override
public String getDescription() {
return "综合咖啡";
}
@Override
public double cost() {
return 12.0;
}
}
public class Decaf implements Beverage {
@Override
public String getDescription() {
return "低因咖啡";
}
@Override
public double cost() {
return 13.0;
}
}
// 3. 抽象装饰者(Decorator)- 调料装饰器
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public abstract String getDescription();
}
// 4. 具体装饰者(ConcreteDecorator)- 各种调料
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加牛奶";
}
@Override
public double cost() {
return beverage.cost() + 3.0;
}
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加摩卡";
}
@Override
public double cost() {
return beverage.cost() + 5.0;
}
}
public class Whip extends CondimentDecorator {
public Whip(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加奶泡";
}
@Override
public double cost() {
return beverage.cost() + 4.0;
}
}
public class Soy extends CondimentDecorator {
public Soy(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加豆浆";
}
@Override
public double cost() {
return beverage.cost() + 4.5;
}
}
客户端测试代码
public class CoffeeShop {
public static void main(String[] args) {
System.out.println("=== 咖啡店点餐系统 ===\n");
// 1. 点一杯纯浓缩咖啡
Beverage espresso = new Espresso();
System.out.println("订单1: " + espresso.getDescription());
System.out.println("价格: $" + espresso.cost() + "\n");
// 2. 点一杯综合咖啡,加双份摩卡和牛奶
Beverage houseBlend = new HouseBlend();
houseBlend = new Mocha(houseBlend);
houseBlend = new Mocha(houseBlend); // 双份摩卡
houseBlend = new Milk(houseBlend);
System.out.println("订单2: " + houseBlend.getDescription());
System.out.println("价格: $" + houseBlend.cost() + "\n");
// 3. 点一杯低因咖啡,加豆浆和奶泡
Beverage decaf = new Decaf();
decaf = new Soy(decaf);
decaf = new Whip(decaf);
System.out.println("订单3: " + decaf.getDescription());
System.out.println("价格: $" + decaf.cost() + "\n");
// 4. 一份豪华套餐:浓缩咖啡加所有调料
Beverage deluxe = new Espresso();
deluxe = new Milk(deluxe);
deluxe = new Mocha(deluxe);
deluxe = new Whip(deluxe);
deluxe = new Soy(deluxe);
System.out.println("订单4: " + deluxe.getDescription());
System.out.println("价格: $" + deluxe.cost());
}
}
运行结果
=== 咖啡店点餐系统 ===
订单1: 浓缩咖啡
价格: $15.0
订单2: 综合咖啡, 加摩卡, 加摩卡, 加牛奶
价格: $25.0
订单3: 低因咖啡, 加豆浆, 加奶泡
价格: $21.5
订单4: 浓缩咖啡, 加牛奶, 加摩卡, 加奶泡, 加豆浆
价格: $31.5
进阶版:带容量大小的咖啡
// 增加容量选项
public enum Size {
TALL, // 小杯
GRANDE, // 中杯
VENTI // 大杯
}
// 修改抽象组件接口
public interface Beverage {
String getDescription();
double cost();
Size getSize();
void setSize(Size size);
}
// 重写具体组件
public class Espresso implements Beverage {
private Size size = Size.GRANDE;
@Override
public String getDescription() {
return "浓缩咖啡";
}
@Override
public double cost() {
// 根据容量计算价格
switch(size) {
case TALL: return 15.0;
case GRANDE: return 18.0;
case VENTI: return 21.0;
default: return 15.0;
}
}
@Override
public Size getSize() {
return size;
}
@Override
public void setSize(Size size) {
this.size = size;
}
}
// 重写装饰者,根据容量计算调料价格
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public Size getSize() {
return beverage.getSize();
}
@Override
public void setSize(Size size) {
beverage.setSize(size);
}
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加摩卡";
}
@Override
public double cost() {
// 摩卡根据不同容量加价
double mochaCost = 5.0;
if (getSize() == Size.TALL) {
mochaCost = 4.0;
} else if (getSize() == Size.VENTI) {
mochaCost = 6.0;
}
return beverage.cost() + mochaCost;
}
}
装饰者模式的优势
优点:
- 组合优于继承:动态地添加职责,比继承更灵活
- 开闭原则:可以在不修改原有代码的情况下添加新功能
- 可选组合:可以自由组合,产生丰富的效果
缺点:
- 增加复杂度:会产生很多小类,增加理解难度
- 调试困难:多层包装使调试变得复杂
- 顺序依赖:某些场景下装饰顺序可能影响最终结果
适用场景
- 需要动态、透明地给单个对象添加职责
- 需要扩展一个类的功能,或给一个类增加附加责任
- 需要动态撤销或恢复对象的某些功能
这个案例完整展示了Java装饰者模式的核心概念:通过包装对象来动态添加功能,而不是通过继承来静态地增加功能。