设置属性P后需要调用方法M
Require calling method M after setting property P
我有一个属性和一个方法:
class C {
var myProperty = ""
func myFunc() {
}
}
我想制定一条规则,当您设置 myProperty
时,您 必须 然后继续调用 myFunc
。当然,我可以有一个 mental 规则来要求这个,但是心理契约根本就不是契约。我想通过class的API.
执行这份合同
(注意 所有这些纯粹是关于 C 内部发生的事情。myProperty
和 myFunc
就可见性 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() })
}()
}
我有一个属性和一个方法:
class C {
var myProperty = ""
func myFunc() {
}
}
我想制定一条规则,当您设置 myProperty
时,您 必须 然后继续调用 myFunc
。当然,我可以有一个 mental 规则来要求这个,但是心理契约根本就不是契约。我想通过class的API.
(注意 所有这些纯粹是关于 C 内部发生的事情。myProperty
和 myFunc
就可见性 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() })
}()
}