如何使用stucts协议来模拟类继承

时间:2017-08-24 18:29:06

标签: swift inheritance swift-protocols

我正在实施一个模型:

  • 结构ClientSummaryClientDetails
  • ClientDetails struct具有ClientSummary struct的所有属性+一些额外属性
  • 两个结构都有主初始值设定项init(jsonDictionary: [String: Any])
  • inits ClientSummaryClientDetails共享代码的大部分内容
  • 有一个扩展可以使用这些结构的共享功能。

我想到的最简单的解决方案就是经典继承,但它不适用于值类型。

我正在尝试用协议解决这个问题,但我无法实现那些“共享内容”。我试图将init的共享部分移动到协议扩展但不能真正实现它。有各种各样的错误。

这是测试代码。

protocol Client {
    var name: String { get }
    var age: Int { get }
    var dateOfBirth: Date { get }

    init?(jsonDictionary: [String: Any])
}


struct ClientSummary: Client {
    let name: String
    let age: Int
    let dateOfBirth: Date

    init?(jsonDictionary: [String: Any]) {
        guard let name = jsonDictionary["name"] as? String else {
            return nil
        }
        self.name = name
        age = 1
        dateOfBirth = Date()
    }
}

struct ClientDetails: Client {
    let name: String
    let age: Int
    let dateOfBirth: Date
    let visitHistory: [Date: String]?

    init?(jsonDictionary: [String: Any]) {
        guard let name = jsonDictionary["name"] as? String else {
            return nil
        }
        self.name = name
        age = 1
        dateOfBirth = Date()
        visitHistory = [Date(): "Test"]
    }
}

extension Client {
    // A lot of helper methods here
    var stringDOB: String {
        return formatter.string(from: dateOfBirth)
    }
}

2 个答案:

答案 0 :(得分:4)

继承是错误的工具。说"详细信息IS-A摘要是没有意义的。"详细信息不是摘要的。离开他们是否分享很多方法的结构性问题,并关注一个人是否是另一种的基本问题。 (有时重命名事物可以做到这一点,但只要他们重新"摘要"和"细节"继承是没有意义的。)

有意义的是说明详细信息HAS-A。构成,而不是继承。所以你结束了类似的事情:

struct ClientDetails {
    let summary: ClientSummary
    let visitHistory: [Date: String]?

    init?(jsonDictionary: [String: Any]) {
        guard let summary = ClientSummary(jsonDictionary: jsonDictionary) else {
            return nil
        }
        self.summary = summary
        visitHistory = [Date(): "Test"]
    }

    // You can add these if you need them, or to conform to Client if that's still useful.
    var name: String { return summary.name }
    var age: Int { return summary.age }
    var dateOfBirth: Date { return summary.dateOfBirth }
}

答案 1 :(得分:0)

我经常希望Swift有一种内置的方法来分离出部分init方法。但是,对于元组来说,它可以做得有点笨拙,如下所示:

struct S {
    let foo: String
    let bar: Int
    let baz: Bool

    init() {
        (self.foo, self.bar, self.baz) = S.sharedSetup()
    }

    static func sharedSetup() -> (String, Int, Bool) {
        ...
    }
}

在您的情况下,可以将sharedSetup()方法移动到协议扩展,或者方便它的任何地方。