You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java披萨装饰器模式实现问题:配料未加入TopingDecorator集合

装饰器模式实现披萨配料系统的正确方案

嘿,我来帮你搞定这个装饰器模式的披萨程序问题!看起来你之前尝试用ArrayList来存储配料的思路走偏了——装饰器模式的核心是层层包装对象,而不是在基础披萨里维护一个配料列表。我给你整理了完整的正确实现,包括你需要的两种披萨和四种配料,还有添加三种配料的示例。

核心结构说明

装饰器模式的关键是:

  • 抽象的Pizza类定义所有披萨(包括基础披萨和带配料的披萨)的通用行为
  • ToppingDecorator作为抽象装饰器,持有一个Pizza对象的引用,用来包装底层披萨
  • 具体配料类继承ToppingDecorator,重写方法来添加自己的描述和成本

1. 抽象披萨类

首先定义所有披萨的基础接口:

public abstract class Pizza {
    protected String description = "Unknown Pizza";
    
    public String getDescription() {
        return description;
    }
    
    public abstract double getCost();
}

2. 具体基础披萨类

实现你需要的美式和那不勒斯披萨:

// 美式披萨
public class American extends Pizza {
    public American() {
        description = "American Pizza";
    }
    
    @Override
    public double getCost() {
        return 8.99; // 基础价格
    }
}

// 那不勒斯披萨
public class Neapolitan extends Pizza {
    public Neapolitan() {
        description = "Neapolitan Pizza";
    }
    
    @Override
    public double getCost() {
        return 9.99; // 基础价格
    }
}

3. 抽象配料装饰器

这个类是装饰器模式的核心,它继承自Pizza,同时持有一个Pizza对象的引用,用来包装底层的披萨(可以是基础披萨,也可以是已经加过配料的披萨):

public abstract class ToppingDecorator extends Pizza {
    protected Pizza pizza;
    
    public ToppingDecorator(Pizza pizza) {
        this.pizza = pizza;
    }
    
    // 默认转发底层披萨的描述和成本,具体配料类会重写这些方法
    @Override
    public String getDescription() {
        return pizza.getDescription();
    }
    
    @Override
    public double getCost() {
        return pizza.getCost();
    }
}

4. 具体配料类

实现你需要的四种配料,每个都继承ToppingDecorator,并添加自己的信息:

// 萨拉米配料
public class Salami extends ToppingDecorator {
    public Salami(Pizza pizza) {
        super(pizza);
    }
    
    @Override
    public String getDescription() {
        return pizza.getDescription() + ", Salami";
    }
    
    @Override
    public double getCost() {
        return pizza.getCost() + 1.50; // 配料价格
    }
}

// 苏杜克香肠配料
public class Soudjouk extends ToppingDecorator {
    public Soudjouk(Pizza pizza) {
        super(pizza);
    }
    
    @Override
    public String getDescription() {
        return pizza.getDescription() + ", Soudjouk";
    }
    
    @Override
    public double getCost() {
        return pizza.getCost() + 1.75;
    }
}

// 洋葱配料
public class Onion extends ToppingDecorator {
    public Onion(Pizza pizza) {
        super(pizza);
    }
    
    @Override
    public String getDescription() {
        return pizza.getDescription() + ", Onion";
    }
    
    @Override
    public double getCost() {
        return pizza.getCost() + 0.75;
    }
}

// 辣椒配料
public class Pepper extends ToppingDecorator {
    public Pepper(Pizza pizza) {
        super(pizza);
    }
    
    @Override
    public String getDescription() {
        return pizza.getDescription() + ", Pepper";
    }
    
    @Override
    public double getCost() {
        return pizza.getCost() + 0.50;
    }
}

添加配料的正确方式

按照你说的“Add Pizza”指令,我们可以像这样给披萨添加三种配料(比如给美式披萨加萨拉米、苏杜克香肠和洋葱):

public class PizzaOrderDemo {
    public static void main(String[] args) {
        // 1. 创建基础美式披萨
        Pizza myPizza = new American();
        
        // 2. 添加第一种配料:萨拉米
        myPizza = new Salami(myPizza);
        
        // 3. 添加第二种配料:苏杜克香肠
        myPizza = new Soudjouk(myPizza);
        
        // 4. 添加第三种配料:洋葱
        myPizza = new Onion(myPizza);
        
        // 输出订单信息
        System.out.println("Your Pizza: " + myPizza.getDescription());
        System.out.println("Total Cost: $" + String.format("%.2f", myPizza.getCost()));
    }
}

运行这段代码,你会得到这样的输出:

Your Pizza: American Pizza, Salami, Soudjouk, Onion
Total Cost: $13.09

为什么之前的ArrayList方式不对?

装饰器模式的设计初衷是动态地给对象添加额外职责,通过层层包装的方式,而不是在基础披萨里维护一个配料列表:

  • 如果用ArrayList存储配料,会把披萨和配料的逻辑耦合在一起,违反了开闭原则(添加新配料时需要修改Pizza类)
  • 装饰器模式让每个配料都是独立的类,符合单一职责原则,修改某个配料的价格或描述不会影响其他部分
  • 你可以灵活组合任意多种配料,甚至调整添加顺序,完全不需要修改现有代码

内容的提问来源于stack exchange,提问作者Habil Ganbarli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:39:57