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

Java装饰器模式实现披萨配料:如何处理文件订单动态添加

嘿,这个动态给披萨应用装饰器的需求我之前也碰到过,刚好可以结合装饰器模式的特性来优雅解决,给你分享个靠谱的实现思路!

核心思路

装饰器模式的关键是用装饰器类嵌套包装基础对象,要实现动态添加,我们只需要:

  1. 解析输入文件,提取订单ID和需要添加的配料列表
  2. 建立配料名称到对应装饰器类的映射
  3. 遍历配料列表,依次用对应的装饰器包装当前披萨实例

具体实现步骤

1. 输入解析

首先要把输入行拆成有用的部分:

  • 输入示例:AddTopping 7 HotPepper Soudjouk Salami
  • 拆分后:命令AddTopping、订单ID7、配料列表[HotPepper, Soudjouk, Salami]

可以用字符串分割来实现,注意处理空格和无效行的情况。

2. 配料映射:用工厂模式替代硬编码

直接根据字符串创建类实例,最安全易维护的方式是用工厂类,把配料名称和对应的装饰器构造逻辑绑定起来,避免硬编码和反射的潜在问题。

3. 动态装饰披萨

先创建基础披萨实例,然后遍历配料列表,每次用工厂生成的装饰器包装当前披萨——这和你手动写new Salami(new Pepper(new Onion(pizza)))的效果完全一致!

完整代码示例

基础披萨与装饰器类(先确保你的类结构是这样)

public abstract class Pizza {
    public abstract String getDescription();
    public abstract double getCost();
}

// 基础披萨类
public class PizzaBakery extends Pizza {
    @Override
    public String getDescription() {
        return "Basic Pizza";
    }

    @Override
    public double getCost() {
        return 5.0;
    }
}

// 示例配料装饰器:HotPepper
public class HotPepper extends Pizza {
    private final Pizza pizza;

    public HotPepper(Pizza pizza) {
        this.pizza = pizza;
    }

    @Override
    public String getDescription() {
        return pizza.getDescription() + ", Hot Pepper";
    }

    @Override
    public double getCost() {
        return pizza.getCost() + 1.5;
    }
}

// 同理实现Soudjouk、Salami等其他配料类...

配料工厂类

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class ToppingFactory {
    // 注册配料名称到装饰器构造逻辑的映射
    private static final Map<String, Function<Pizza, Pizza>> TOPPING_MAP = new HashMap<>();

    static {
        // 把每个配料的构造函数注册进来,键要和输入文件里的名称完全匹配
        TOPPING_MAP.put("HotPepper", HotPepper::new);
        TOPPING_MAP.put("Soudjouk", Soudjouk::new);
        TOPPING_MAP.put("Salami", Salami::new);
        TOPPING_MAP.put("Onion", Onion::new);
        TOPPING_MAP.put("Pepper", Pepper::new);
        // 新增配料只需要在这里加一行就行
    }

    public static Pizza applyTopping(String toppingName, Pizza pizza) {
        Function<Pizza, Pizza> toppingCreator = TOPPING_MAP.get(toppingName);
        if (toppingCreator == null) {
            throw new IllegalArgumentException("Unknown topping: " + toppingName);
        }
        return toppingCreator.apply(pizza);
    }
}

订单处理类(读取文件+动态装饰)

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class PizzaOrderProcessor {
    public static void main(String[] args) {
        String orderFilePath = "your_orders.txt"; // 替换成你的输入文件路径

        try (BufferedReader reader = new BufferedReader(new FileReader(orderFilePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                processSingleOrder(line);
            }
        } catch (IOException e) {
            System.err.println("Failed to read order file: " + e.getMessage());
        }
    }

    private static void processSingleOrder(String line) {
        String[] parts = line.trim().split("\\s+");
        // 校验输入格式是否合法
        if (parts.length < 3 || !"AddTopping".equals(parts[0])) {
            System.err.println("Skipping invalid order line: " + line);
            return;
        }

        // 提取订单ID和配料列表
        String orderId = parts[1];
        String[] toppings = new String[parts.length - 2];
        System.arraycopy(parts, 2, toppings, 0, toppings.length);

        // 初始化基础披萨
        Pizza pizza = new PizzaBakery();

        // 动态应用所有配料装饰器
        for (String topping : toppings) {
            pizza = ToppingFactory.applyTopping(topping, pizza);
        }

        // 输出订单结果
        System.out.printf("Order #%s%nFinal Pizza: %s%nTotal Cost: $%.2f%n%n",
                orderId, pizza.getDescription(), pizza.getCost());
    }
}

备选方案:用反射实现(不推荐)

如果觉得工厂模式需要手动注册太麻烦,也可以用反射动态创建装饰器实例,但这种方式类型安全性差,而且如果类名和输入名称不一致还要额外处理映射,示例代码如下:

import java.lang.reflect.Constructor;

public class ReflectiveToppingFactory {
    // 假设所有配料类都在同一个包下,比如com.yourproject.toppings
    private static final String TOPPING_PACKAGE = "com.yourproject.toppings";

    public static Pizza applyTopping(String toppingName, Pizza pizza) {
        try {
            Class<?> toppingClass = Class.forName(TOPPING_PACKAGE + "." + toppingName);
            Constructor<?> constructor = toppingClass.getConstructor(Pizza.class);
            return (Pizza) constructor.newInstance(pizza);
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to create topping: " + toppingName, e);
        }
    }
}

还是更推荐工厂模式,代码更清晰,排查问题也更方便,新增配料只需要在工厂里加一行注册代码就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:48:59