在Swift中使用value objects

753 阅读1分钟

验证用户名的代码

func authenticate(user: String) {
    // make sure usernames are at least three characters
    guard user.trimmingCharacters(in: .whitespacesAndNewlines).count >= 3 else {
        print("Username \(user) is too short.")
        return
    }

    // make sure usernames contain no invalid characters
    let illegalCharacters = ["@", "-", "&", "."]
    guard illegalCharacters.contains(where: user.contains) == false else {
        print("Username \(user) contains illegal characters.")
        return
    }

    // Proceed with authentication…
}
``` swift
上面代码的缺点:在其他地方使用会重复

``` swift
extension String {
    func isValidUsername() -> Bool {
        guard self.trimmingCharacters(in: .whitespacesAndNewlines).count >= 3 else {
            return false
        }

        let illegalCharacters = ["@", "-", "&", "."]
        guard illegalCharacters.contains(where: self.contains) == false else {
            return false
        }

        return true
    }
}

上面代码的缺点:需要在每个地方调用isValidUsername()

struct User: Equatable {
    let value: String

    init?(string: String) {
        guard string.trimmingCharacters(in: .whitespacesAndNewlines).count >= 3 else {
            return nil
        }

        let illegalCharacters = ["@", "-", "&", "."]
        guard illegalCharacters.contains(where: string.contains) == false else {
            return nil
        }

        self.value = string
    }
}

func authenticate(user: User) {
    // Proceed with authentication…
}

值对象:value objects should be both immutable and equatable, but they also add in validation as part of their creation. This means that if you’re handed a value object you know for sure it’s already passed validation – you don’t need to re-validate it, because if it were valid then it couldn’t exist.

设计:参考系统的 URL(string: "This ain't it chief") 好处:安全,扩展性强

注:contains与allSatisfy的区别

// 有一个满足就为true
func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool
// 所以满足就为true
func allSatisfy(_ predicate: (Element) throws -> Bool) rethrows -> Bool

参考:Improving your Swift code using value objects