在纯 OO 代码中使用时,开关是一种代码味道。这并不意味着它们在定义上是错误的,只是你需要三思而后行。要格外小心。
我在这里对 switch 的定义还包括 if-then-else 语句,这些语句可以很容易地重写为 switch 语句。
开关可能表明您没有定义接近其操作的数据的行为,并且没有利用例如子类型多态性。
使用 OO 语言时,您不会被迫以 OO 方式进行编程。因此,如果您选择使用更具功能性或基于对象的编程风格(例如,使用仅包含数据但不包含行为的 DTO,而不是更丰富的域模型),使用开关没有任何问题。
最后,在编写 OO 程序时,开关在您的 OO 模型的“边缘”非常方便,当某些东西从非 OO 外部世界进入您的 OO 模型并且您需要将此外部实体转换为 OO 概念时。你最好尽早这样做。例如:数据库中的 int 可以使用开关转换为对象。
int dbValue = ...;
switch (dbValue)
{
case 0: return new DogBehaviour();
case 1: return new CatBehaviour();
...
default: throw new IllegalArgumentException("cannot convert into behaviour:" + dbValue);
}
阅读一些回复后进行编辑。
Customer.isInvestable
: 很好,多态。但是现在您将此逻辑与客户联系起来,您需要为每种类型的客户创建一个子类,以实现不同的行为。上次我检查时,这不是应该使用继承的方式。您可能希望客户类型是 的属性Customer
,或者具有可以决定客户类型的函数。
双分派:多态两次。但是你的访问者类本质上仍然是一个很大的转变,它有一些与上面解释的相同的问题。
此外,按照 OP 的示例,多态性应该在客户的类别上,而不是在Customer
其自身上。
切换一个值很好:好的,但是 switch 语句在大多数情况下用于测试单个int
, char
, enum
, ... 值,而不是 if-then-else 可以测试范围和更奇特的条件。但是如果我们在这个单一的值上进行调度,并且它不像上面解释的那样位于我们的 OO 模型的边缘,那么似乎开关经常被用来在类型上调度,而不是在一个值上。或者:如果你不能用 switch 替换 if-then-else 的条件逻辑,那么你可能没问题,否则你可能不行。因此,我认为 OOP 中的开关是代码异味,而声明
打开类型是不好的 OOP 风格,打开一个值就可以了。
本身就过于简单化了。
回到起点:aswitch
还不错,只是并不总是非常 OO。您不必使用 OO 来解决您的问题。如果您确实使用 OOP,那么您需要特别注意开关。