我有一个属性和一个方法:
class C {
var myProperty = ""
func myFunc() {
}
}
我希望有一个规则,当您设置myProperty
时,您必须 然后继续呼叫myFunc
。当然,我可以有一个 mental 规则,要求这样做,但是精神契约根本不是契约。我想通过类的API 执行该合同。
(注意,所有这些纯粹是关于内部 C的内容。myProperty
和myFunc
都可以是私有的 outside C;这不会影响问题。)
很明显,我们可以使用二传手观察者来做到这一点:
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()
}
}
但是 存在一个问题,即现在可以在不调用myProperty
的情况下设置myFunc
,从而打破了我们首先要执行的规则地点!我发现执行该规则的唯一方法是拥有另一个类,该类可以保护隐私。例如:
class C3 {
class Inner {
private(set) var myProperty = ""
private func myFunc() {
}
func setMyPropertyAndCallMyFunc(_ s:String) {
self.myProperty = s
self.myFunc()
}
}
let inner = Inner()
}
这实际上是我正在做的事情,但是拥有第二类只是为了执行这些隐私和命名规则似乎有点坚果。我的问题是:还有另一种方法吗?
答案 0 :(得分:1)
是的,尽管我不知道它是否真的更好。您可以将myProperty
隐藏在闭包内部,而不是隐藏在类/结构内部。例如:
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 = $1; $0.myFunc() })
}()
}
let c = C()
c.myProperty
c.setMyPropertyAndCallMyFunc(value: "x")
c.myProperty
这里有很多复杂性,例如将self
传递给_setMyPropertyAndCallMyFunc
来允许myFunc
生活在闭包之外,也许可以省去其中的一部分。但是基本思想是生成两个函数,这是唯一可以访问属性存储的函数,从而使其在不创建内部类的情况下成为“超级私有”。
如果您不需要公开myFunc()
(并且从您的Inner示例中,我认为您不需要公开),则可以更简单一些,这可能比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 = $0; myFunc() })
}()
}