你在这里所拥有的是一个委托模式。您的委托属性仅称为class1Obj,而不是更习惯的delegate 名称。这里的关键问题是您没有使用协议,因此这两个类是“紧密耦合的”,即Class2 高度依赖于Class1 实现的细节。此外,对于这两个紧密耦合的类,尚不清楚Class2 可能需要哪些Class1 方法。它使Class1 的维护变得更加困难,因为很容易意外地做出破坏Class2 行为的更改。这也使得Class2 难以与Class1 以外的其他类一起使用。
相反,您通常会声明一个协议,以准确阐明Class2 和其他可能需要使用它的对象之间的合同性质。结果是这些类的耦合不那么紧密,即Class2 除了与相关协议的一致性之外,不需要知道其他类的任何信息。此外,在编辑Class1时,如果你声明它符合协议,编译器会在你未能实现某些必需的方法或属性时发出警告。
因此,在前期工作量可以忽略不计的情况下,该协议使代码更易于维护。它还提供了一些额外的灵活性,您将来可以将Class2 与Class1 以外的其他内容结合使用。
最重要的是,协议可以使代码更易于维护且更灵活,没有隐藏的假设。
如果您不想使用委托协议模式,另一种选择是使用闭包,其中Class1 提供Class2 可以调用的代码块。所以你可以这样做:
class Class1 {
var class2Obj = Class2()
init() {
class2Obj.handler = { [weak self] in // note `weak` reference which avoids strong reference cycle
self?.class1Method()
}
}
func class1Method() {
print("Parent")
}
}
class Class2 {
var handler: (() -> Void)?
func class2Method() {
handler?()
}
}
当两个类之间有一个丰富的接口时,委托协议模式很有用,而当两个类之间有一个非常简单的接口时,这个闭包模式很有用。
坦率地说,上述更常见的排列是闭包更直接地与Class1 在Class2 中发起的某些特定请求相关联。因此,您可能只是将参数设置为Class2 中适当方法的闭包。此外,您经常将数据传回,所以假设我们传回一个可选的String:
class Class1 {
var class2Obj = Class2()
func performClass2Method() {
class2Obj.class2Method { string in
guard let string = string else { return }
self.class1Method()
}
}
func class1Method() {
print("Parent")
}
}
class Class2 {
func class2Method(completionHandler: @escaping (String?) -> Void) {
// do something which creates `string`
// when done, call the closure, passing that `string` value back
completionHandler(string)
}
}
这些闭包模式是在对象之间进行简单接口的好方法,但也使两个类保持非常松散的耦合(即Class2 不依赖于Class1),就像在委托模式中使用协议一样。但希望上述闭包示例说明了丰富的委托协议模式的简单替代方案。