解析时避免使用 switch 语句

Avoid the usage of a switch statement when parsing

我一直在努力开发一个代码来避免大的 switch 语句。

基本上我得到了一组元组作为输入,现在我想根据元组中指定的类型实例化适当的 class(元组的第一个元素 - 例如(“Apple”, ...)).

目前我通过使用 switch 语句解决了我的问题,但是如果将来 classes 的数量增加,这是一个非常糟糕的主意。有什么优雅的方法可以规避这个问题吗?

谢谢!

class Apple {
    var color = ""
}

class Banana {
    var isTasty = false
}

let input = [("Apple", "green"),("Banana", "TRUE")]

for (type, value) in input {
    switch type {
    case "Apple":
        Apple()
    case "Banana":
        Banana()
    default:
        print(value)
    }
}

看看这个,

// Parent Class to group them
class Fruit {
    var baseValue: Any
    required init(_ this: Any) {
        baseValue = this
        (self as? Apple)?.color = this as! String
        (self as? Banana)?.isTasty = this as! Bool
        // You can add more subclasses here
    }
}

class Apple: Fruit, Equatable {
    var color = ""
    
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(color)
    }
    static func == (lhs: Apple, rhs: Apple) -> Bool {
        return lhs.color == rhs.color
    }
}

class Banana: Fruit, Equatable {
    var isTasty = false
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(isTasty)
    }
    static func == (lhs: Banana, rhs: Banana) -> Bool {
        return lhs.isTasty == rhs.isTasty
    }
}

有点烦人的是它们必须符合 Fruit、Hashable 和 Equatable。但它让你这样做,这回答了你的问题:

let input: [(Fruit.Type,Any)] = [(Apple.self, "green"),(Banana.self, true)]

for (type, value) in input {
    // Now you don't need that switch statement
    let foo = type.init(value)
    // Now you can use `as?` to find out what it is
    
    print((foo as? Banana)?.isTasty)
    // See, it prints `nil` first, then `Optional(true)` next.
    // Which is how we want it to run
}


不过,我认为我们可以做得更好。

enum Fruit {
    case apple(color: String)
    case banana(isTasty: Bool)
}

let input: [Fruit] = [.apple(color: "red"), .banana(isTasty: true)]

好多了。