设置属性P后需要调用方法M

Require calling method M after setting property P

我有一个属性和一个方法:

class C {
    var myProperty = ""
    func myFunc() {

    }
}

我想制定一条规则,当您设置 myProperty 时,您 必须 然后继续调用 myFunc。当然,我可以有一个 mental 规则来要求这个,但是心理契约根本就不是契约。我想通过class的API.

执行这份合同

(注意 所有这些纯粹是关于 C 内部发生的事情。myPropertymyFunc 就可见性 outside C 而言可以是私有的;这不会影响问题。)

显然我们可以用 setter 观察者来做到这一点:

class C1 {
    var myProperty = "" {
        didSet {
            self.myFunc()
        }
    }
    func myFunc() {

    }
}

但是,我不喜欢该解决方案:它依赖于隐藏的副作用。我知道说 self.myProperty = "..." 也会触发对 myFunc 的调用。我不喜欢那种隐藏的副作用;它使我的代码更难理解,并且违反了我的一项关键编程原则,说出你的意思。

我的意思是做什么?我的意思是这样的:

self.setMyPropertyAndCallMyFunc("...")

我喜欢这样,因为它准确地告诉我每次调用在我的代码中执行的操作。所以我们可以这样写:

class C2 {
    var myProperty = ""
    func myFunc() {

    }
    func setMyPropertyAndCallMyFunc(_ s:String) {
        self.myProperty = s
        self.myFunc()
    }
}

但是 that 有一个问题,即现在可以在不调用 myFunc 的情况下设置 myProperty,打破了我们制定的规则第一时间强制执行!我发现执行该规则的唯一方法是让 另一个 class 保护 属性 的隐私。例如:

class C3 {
    class Inner {
        private(set) var myProperty = ""
        private func myFunc() {

        }
        func setMyPropertyAndCallMyFunc(_ s:String) {
            self.myProperty = s
            self.myFunc()
        }
    }
    let inner = Inner()
}

事实上,这就是我正在做的事情,但是为了强制执行这些隐私和命名规则而有第二个 class 似乎有点疯狂。我的问题是:还有其他方法吗?

是的,虽然我不知道它是否真的更好。您可以将 myProperty 隐藏在闭包内部而不是 class/struct 内部。例如:

class C {
    public var myProperty: String { return _myPropertyGetter() }
    public func setMyPropertyAndCallMyFunc(value: String) {
        _myPropertySetter(self, value)
    }

    func myFunc() {
        print("myFunc")
    }

    private let (_myPropertyGetter, _myPropertySetter): (() -> String, (C, String) -> ()) = {
        var property = ""
        return ({ property }, { property = ; [=10=].myFunc() })
    }()
}

let c = C()
c.myProperty
c.setMyPropertyAndCallMyFunc(value: "x")
c.myProperty

这里有很多复杂性,比如将 self 传递给 _setMyPropertyAndCallMyFunc 以允许 myFunc 存在于闭包之外,也许其中一些可以省去。但基本思想是生成两个函数,它们是唯一可以访问 属性 存储的函数,使其成为 "super-private" 而无需创建内部 class.

如果你不需要 myFunc() 成为 public(从你的内部例子来看,我认为你不需要),那么你可以做得更简单一点,这几乎可能比 Inner 好。

class C {
    public var myProperty: String { return _myPropertyGetter() }
    public func setMyPropertyAndCallMyFunc(value: String) { _myPropertySetter(value) }

    private let (_myPropertyGetter, _myPropertySetter): (() -> String, (String) -> ()) = {
        var property = ""
        func myFunc() {
            print("myFunc")
        }
        return ({ property }, { property = [=11=]; myFunc() })
    }()
}