有没有人不同意“使用switch是糟糕的OOP风格”的说法?

2022-09-01 14:49:55

我已经看到它写在堆栈溢出的多个线程/评论中,使用它只是糟糕的OOP风格。就我个人而言,我不同意这一点。switch

在许多情况下,您无法将代码(即方法)添加到要打开的类中,因为您无法控制它们,也许它们位于第三方jar文件中。在其他情况下,将功能放在枚举本身上是一个坏主意,因为它违反了一些关注点分离的注意事项,或者它实际上是其他东西的功能以及枚举enum

最后,开关简洁明了:

boolean investable;
switch (customer.getCategory()) {
    case SUB_PRIME:
    case MID_PRIME:
        investible = customer.getSavingsAccount().getBalance() > 1e6; break;
    case PRIME:
        investible = customer.isCeo(); break;
}

我不是在为每一种用途辩护,我也不是说这总是要走的路。但是,在我看来,像“Switch是一种代码气味”这样的陈述是错误的。还有其他人同意吗?switch


答案 1

我认为像这样的陈述

使用 switch 语句是错误的 OOP 样式。

Case 语句几乎总是可以用多态性替换。

过于简单化。事实是,打开类型的 case 语句是糟糕的 OOP 样式。这些是您要用多态性替换的。打开一个是可以的。


答案 2

采取您的后续行动:

如果这只是希望获得商业贷款的客户的“可投资性”逻辑,该怎么办?也许客户对另一种产品的可投资性决定真的完全不同......另外,如果一直有新产品问世,每个产品都有不同的可投资性决策,并且我不想每次发生这种情况时都更新我的核心客户类别,该怎么办?

以及您的评论之一:

我不完全确定是否将逻辑保持在接近其运行所基于的数据的位置。现实世界不是这样运作的。当我要求贷款时,银行决定我是否有资格。他们不要求我自己决定。

你是对的,就这一点而言。

boolean investable = customer.isInvestable();

不是您正在谈论的灵活性的最佳解决方案。但是,最初的问题没有提到单独的产品基类的存在。

鉴于现在可用的其他信息,最好的解决方案似乎是

boolean investable = product.isInvestable(customer);

可投资性决策是由产品根据您的“现实世界”论点做出的(多态的!),并且还避免了每次添加产品时都必须创建新的客户子类。产品可以使用任何它想要的方法根据客户的公共接口做出该决定。我仍然会质疑是否可以对客户的界面进行适当的添加以消除切换的需要,但它可能仍然是所有邪恶中最少的。

不过,在提供的特定示例中,我很想做这样的事情:

if (customer.getCategory() < PRIME) {
    investable = customer.getSavingsAccount().getBalance() > 1e6;
} else {
    investable = customer.isCeo();
}

我发现这比在开关中列出每个可能的类别更清晰,我怀疑它更有可能反映“现实世界”的思维过程(“它们低于素数吗?”与“它们是次素数还是中素数?”),并且如果在某个时候添加了SUPER_PRIME名称,它避免了重新访问此代码。