繁体   English   中英

检查 List 中的元素是否有效且顺序正确

[英]Check if elements in List are valid and in the right order

我正在制作 Subway 餐厅的复制品,您将在其中按特定顺序收到订单,并检查该顺序是否有效以及菜单中是否有食材。

正确的顺序是:1 块面包、0 到 1 块肉、1 块奶酪、1 到 3 份额外食物、1 到 3 种酱汁。

这意味着一个订单可以包含至少 4 种成分(面包、奶酪、1 种额外成分、1 种酱汁)和最多 9 种成分(面包、肉类、奶酪、3 种额外成分、3 种酱汁)。

我的问题是,是否有比我的更优化/更智能的方法来验证每种成分?

代码:

// Example order
HashMap<String, HashSet<String>> menu = new HashMap<>();

public static void main(String[] args) {
    // Example order
    List<String> ingredients = Arrays.asList("Wheat", "Veal",
        "Yellow", "Cucumbers", "Onions");
    if (!isValid(ingredients)) {
        // throw exc;
}
    
    
    
boolean isValid(List<String> ingredients) {
    if (ingredients.size() < 4 || ingredients.size() > 9) {
        return false;
    }
    int i = 0;
    // Bread
    if (!Restaurant.menu.get("Bread")
            .contains(ingredients.get(i++))) {
        System.out.println("Bread");
        return false;
    }
    
    // Meat
    if (!(Restaurant.menu.get("Meat")
            .contains(ingredients.get(i)))
            && !Restaurant.menu.get("Cheese")
                    .contains(ingredients.get(i))) {
        System.out.println("Meat");
        return false;
    }
    
    if (Restaurant.menu.get("Meat")
            .contains(ingredients.get(i))) { // Meat case
        if ((!Restaurant.menu.get("Cheese")
                .contains(ingredients.get(++i)))) {
            System.out.println("Cheese");
            return false;
        }
    }
    
    for (int j = ++i; j < ingredients.size(); j++) {
        if ((!Restaurant.menu.get("Extras")
                .contains(ingredients.get(j)))) { // Extras
            if (j == i) {
                return false;
            } else {
                if ((!Restaurant.menu.get("Sauces")
                        .contains(ingredients.get(j)))) { // Sauces
                    return false;
                }
            }
        }
    }
    
    return true;
}

注意 1:我知道“如果它有效,请不要碰它”的规则,但我觉得这段代码正在进入意大利面条代码的领域,其中有一堆 ifs 基本上检查了很多情况下类似的事情,只是想要一个第二种意见,如果我现在想不出更优化的方式。

注意 2:我为菜单选择了 HashSet 而不是 ArrayList,因为它的搜索速度更快。

我在您提出的解决方案中看到的问题是它试图一次解决所有问题,而不是单独解决它们。 在我看来,这使您的代码难以阅读和理解。 虽然它可能有效,但您添加的业务规则越多,这就越难。

所以你对此能做些什么? 分离关注点。

第一个问题是对一种成分进行分类:是面包、奶酪、肉、额外的还是酱汁? 例如,您可以使用返回类别的方法getCategory() (而不仅仅是对Menu使用HashSet )创建一个菜单类,并且返回值可以是一个枚举。

第二个问题是秩序。 您可以使用自定义Comparator检查列表的顺序。 有关详细信息,请参阅此问题

第三个关注点是某一类别的成分数量。 鉴于您可以找出一种成分的类别,您可以计算您有多少并检查它是否正确。

关于如何实现这一点还有很多话要说,我只是想为您指出一个可能的方向。

首先,您的一般方法没有什么问题。

话虽如此,还是有一些错误。

  • 您通过未声明为静态的 Restaurant 将您的 hashMap 引用为静态值。
  • 您正在从静态上下文(Main)中调用isValid() ) 但该方法未声明为静态的。

这就是我可能接近它的方式。 这也不是说它是最好的方法或风格。

  • 我选择使用enum来保存每个菜单项的详细信息,并使用一个类来处理订单。 Enum 很容易满足这种类型的要求。 我建议您阅读它们(它们过于复杂,无法在此处详细解释)。 但是因为它们是static的,所以它们最好用于持有不太可能改变的值。

  • 每个项目都有两个参数,都在enum's构造函数中处理。

  • 所以每个项目都有一个单独的项目范围(成分)

  • enum还有一个 validate 方法来检查提供的项目计数是否符合要求。

实际订单在MyOrder类中。

  • 它包含一个地图来保存每种成分的数量。
  • add 方法将当前数量添加到给定成分的地图中。
  • 以及打印订单信息的显示方法。
enum Menu {MEAT(0,1), BREAD(1,1), CHEESE(1,1), EXTRAS(1,3), SAUCES(1,3);
    private int min;
    private int max;
    private Menu(int min, int max) {
        this.min = min;
        this.max = max;
    }
    
    public int getMax() {
        return max;
    }
    public int getMin() {
        return min;
    }
    
    public  boolean validate(int count) {
        return count >= min && count <= max;
    }
}
class MyOrder {
    private EnumMap<Menu, Integer> counts = new EnumMap<>(Menu.class);
    
    public void display() {
        for (Menu item : Menu.values()) {
            int count = counts.get(item);
        System.out.printf("%-7s: %d  (%d,%d) %s%n",item.name(), count, item.getMin(), item.getMax(),
                item.validate(count) ? "" : "Item count out of range.");
        }
    }
        
    public boolean add(Menu item, int quantity) {
        return item.validate(counts.merge(item, quantity, Integer::sum));
    }
}
        
public class Restaurant {

    public static void main(String[] args) {
        boolean isValid;
        MyOrder order = new MyOrder();
        isValid =  order.add(Menu.BREAD,2);
        isValid &= order.add(Menu.MEAT,1);
        isValid &= order.add(Menu.CHEESE,2);
        isValid &= order.add(Menu.EXTRAS,3);
        isValid &= order.add(Menu.SAUCES,2);
        if (isValid) {
            System.out.println("Your order is accepted.");
        } else {
            System.out.println("Order is not in compliance");
            order.display();
        }
    }
}

印刷

Order is not in compliance
MEAT   : 1  (0,1) 
BREAD  : 1  (1,1) 
CHEESE : 2  (1,1) Item count out of range.
EXTRAS : 3  (1,3) 
SAUCES : 2  (1,3) 

还要记住,任何if statement的结果都是boolean 因此,可以将inequality分配给布尔值,然后稍后进行测试(如果这样做有意义的话)。 另请注意,我直到最后才检查合法订单。 有些人可能更愿意在订单出现错误时立即发出信号。 这是一种设计选择。

欲了解更多信息检查。
枚举
枚举映射
地图合并

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM