Swift 中的特例模式是否多余?

Is the Special case pattern redundant in Swift?

在 Robert Martin 的 Clean Code 一书中有一个 Java 何时使用 special case pattern 的例子。而不是这样写:

try {
  MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
  expenseTotal += expenses.getTotal();
} catch(MealExpensesNotFound e) {
  expenseTotal += getMealPerDiem();
}

我们会使用:

public class PerDiemMealExpenses implements MealExpenses {
  public int getTotal() {
  // return the per diem default
}

MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
expenseTotal += expenses.getTotal();

在 swift 中我们没有合并,因此我们可以跳过创建 interface/protocol 并立即转到:

let expenses = expenseReportCalculator.getMeals(employee.id)
expenseTotal += expenses.getTotal() ?? getMealPerDiem

这是否意味着使用 Swift 时特例模式是多余的?也许我没有抓住要点,或者在特殊情况下这种模式很有价值。

我同意这个 "special case" 讨论,在 Martin 的优秀文章 错误处理 章节的 定义正常流程 部分Clean Code,有点笨拙。

正如您所指出的,马丁的部分理由是删除重复使用 Java 的 "awkward"(他的话,不是我的话)try-catch 模式,特别是如果你经常重复它。但是在 Swift 中,如果没有开销,您可能不会追求错误抛出模式,而只是 return 一个可选的。而且,正如您所说,Swift nil-合并模式与 try-catch 模式相当优雅。 (顺便说一句,Swift 可选值也与该章的下两节无关,Don't Return NullDon' t 传递 Null.)

Robert Martin 在本次讨论中归功于 Martin Fowler,但在 Refactoring 中,Fowler 讨论了 "special case" 模式在 null 检查 Java 以及随之而来的所有问题。但是 Swift 处理可选值的方式要优雅得多,这使得 Fowler 的大部分防御性讨论变得毫无意义。

所以,我同意,MealExpenses 不是 Swift 中 "special case" 模式的特别好的候选者。 (坦率地说,我不确定它是否是一个很好的候选人,不管怎样。)Optionals 将是一个更自然的 Swift 解决方案。现在,如果我的代码到处都是相同的 nil 合并模式,我会寻找避免重复它的方法,但我不一定会跳到引入 "special case" 模式仅用于此目的。

值得注意的是,在 Refactoring 中,Fowler 提供了一个扩展的 "special case" 示例,其中房东的 "customer" 一些随机建筑可能是 "no customer"(例如建筑物空置)、"unknown customer"(您知道有租户,但不知道是谁)或特定客户。在这种三元状态下,我们必须开始考虑超越简单的 Swift 可选。但那时我们可能会使用带有关联值的 enum,或者你可以想象使用 "special case" 模式(但现在需要引入协议)。这取决于具体情况。尽管如此,我还没有遇到过我倾向于在我的 Swift 代码中添加 "special case" 模式的场景。