[英]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
检查列表的顺序。 有关详细信息,请参阅此问题。
第三个关注点是某一类别的成分数量。 鉴于您可以找出一种成分的类别,您可以计算您有多少并检查它是否正确。
关于如何实现这一点还有很多话要说,我只是想为您指出一个可能的方向。
首先,您的一般方法没有什么问题。
话虽如此,还是有一些错误。
isValid()
) 但该方法未声明为静态的。这就是我可能接近它的方式。 这也不是说它是最好的方法或风格。
我选择使用enum
来保存每个菜单项的详细信息,并使用一个类来处理订单。 Enum 很容易满足这种类型的要求。 我建议您阅读它们(它们过于复杂,无法在此处详细解释)。 但是因为它们是static
的,所以它们最好用于持有不太可能改变的值。
每个项目都有两个参数,都在enum's
构造函数中处理。
所以每个项目都有一个单独的项目范围(成分)
enum
还有一个 validate 方法来检查提供的项目计数是否符合要求。
实际订单在MyOrder
类中。
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.