如何在没有样板的情况下从超类访问内部对象的属性

时间:2019-06-27 01:56:35

标签: swift encapsulation abstraction

是否有一种无需样板即可创建内部对象属性的访问器的方法?

这是带有样板的类的示例

public class Foo {
    internal let bar: Bar

    internal init(bar: Bar) {
        self.bar = bar
    }

    private struct Bar: Codable {
        let id: Int
        let name: String
    }  

    // MARK: - Boilerplate 

    public var id: Int { 
        return self.bar.id
    }

    public var name: String { 
        return self.bar.name
    }
}

// Usage

do {
    let bar: Bar = try data.decoded() 
    let foo = Foo(bar: bar)

    print(foo.id)
    print(foo.name)
} catch {
    ...
}

是否有一种无需编写样板的方法?对于具有更多属性的较大对象,这可能真的很有帮助

请注意:访问控制修饰符很重要

1 个答案:

答案 0 :(得分:2)

Swift 5.1中的新增功能,您可以使用具有关键路径的动态成员查找。这对于这种“ has-a”情况非常有用,因为关键路径保持完整类型检查。这是一个简化的示例(不尝试反映您的实际情况):

struct Dog {
    let name : String
}
@dynamicMemberLookup
struct Kennel {
    let dog : Dog
    subscript(dynamicMember kp:KeyPath<Dog,String>) -> String {
        self.dog[keyPath:kp]
    }
}

结果是,给定狗窝k,我们可以获得k.name作为获取k.dog.name的一种方式。

但是说k.xxx是非法的,因为Dog没有String xxx属性;这就是我说要保留完整类型检查的意思。


旧方法是使用协议。这样,您可以使用协议扩展来注入样板。

protocol HasNameAndId {
    var id: Int {get}
    var name: String {get}
}

protocol WrapperOfHasNameAndId {
    associatedtype T : HasNameAndId
    var bar: T {get}
}

extension WrapperOfHasNameAndId { // boilerplate
    var id: Int {
        return self.bar.id
    }
    var name: String {
        return self.bar.name
    }
}

// ==============

struct Bar: HasNameAndId {
    let id: Int
    let name: String
}

class Foo : WrapperOfHasNameAndId {
    let bar: Bar
    init(bar: Bar) {
        self.bar = bar
    }
}

// =======

let f = Foo(bar: Bar(id: 1, name: "howdy"))
print(f.id) // 1
print(f.name) // "howdy"