使用委托而不是类实例的充分理由?

问题描述 投票:0回答:3

我被问到有关代表的问题,我对正确答案有一些疑问:

当您创建您自己的协议时,使用委托或仅实例化类并调用简单方法之间有什么区别?

我想:有了委托,你就不用费心去实例化一个新的整个类了,你可以在类之外设置委托,只用“委托”来调用方法即可。使用委托来避免无限导入也是一件好事吗?就像当 classA 导入 classB 时,如果您实例化该类而不是使用委托,则 classB 也会导入 classA,并且会导致崩溃?

创建自己的协议/委托时还有其他充分的理由吗?

objective-c delegates protocols
3个回答
1
投票

好吧,看一个例子。

假设您有“某物”,它恰好显示一个窗口,作为其正在执行的操作的一部分。如果没有委托或类似的设置,您必须是“Window”的子类才能处理窗口内容,并且您必须是其他东西的子类才能处理您正在做的任何其他事情。所以这要么是不可能的,要么你就会陷入各种多重继承的怪异之中。

因此,您可能最终会创建一个任何东西的子类,以及“Window”的子类,并实例化两者的对象,并让它们以某种方式进行通信。这正是代表所做的事情,只不过您必须为各种事情一遍又一遍地执行此操作。就像想象一个窗口中有 10 个按钮,每个按钮都需要一个按钮子类,除了在实际类上调用“ButtonXClicked”之外,它实际上并没有做太多事情。再次,看看这里重新实现的“委托”(是的,在 Cocoa 中它不是委托;那将是目标/操作。但它与委托并没有什么不同)?

因此,委托非常方便地连接那些实际上不具有派生类所暗示的“某种”关系的对象。

它还允许您连接“在其他地方创建”的对象,就像当您有创建对象并将其返回给您的东西时:您不能真正在那里替换子类,但 API 可能仍然允许您执行“setDelegate:”类似的东西将该对象连接到您的应用程序。

有时委托更合适,有时子类更好,而且在某些情况下这可能并不重要。


1
投票

我认为委托的主要优点是它们允许您在运行时更改对象的行为。它们还有助于加强功能区域之间的分离。

我们看一个具体的例子:

NSTableView
的数据源。
NSTableView
为 OS X 中的表提供 UI 实现。数据源委托提供获取数据以填充表的功能。

在我开始使用 Objective-C 并使用 C++ 和 Java 进行编程之前,我会通过 UI 类实现表视图,该 UI 类具有一些受保护的方法来管理数据,这些数据将被子类化以创建不同的表视图。

这种方法完全有效,但它混合了管理数据的功能和显示的功能,并且不太灵活。一旦您说过小部件 X 是一个以某种方式访问数据的表视图,那就一切都是板上钉钉的了。如果您希望小部件 X 以不同的方式获取其数据,您必须将这种灵活性构建到 UI 类中,或者销毁它并从不同的子类重新创建它。

另一方面,委托模式允许

NSTableView
通过简单的分配和重新加载来完全更改其数据源。此外,UI 类不会被数据处理代码污染,数据处理类也不会被 UI 处理代码污染。

你可以在不使用协议的情况下进行委托,事实上,在 Cocoa 10.5 之前的版本中,这是常态而不是例外,但是,如果你使用协议来定义委托 API,你将获得编译器对委托错误检查的支持实施和最低限度的文档。


0
投票

这个问题是一个概括性问题。最好避免无限制导入。

想象一下这个场景。您有一个运行的计时器(来自名为 KDTimer 的类),并在某个时刻到期。现在你想在 3 种游戏模式 A、B 和 C 中使用它(它们都对应于 3 个不同的类别)。现在,不同的游戏模式会对计时器到期做出不同的反应。您得到的差异是:

代表:

您在 KDTimer 中定义协议,将 a、b 或 c 设置为它的委托(实际上 a、b 或 c 将自己设置为计时器委托),然后执行

-(void) increaseProgress {
//incrementProgress
if(self.progress>=1) 
[_delegate timeExpired];
}

你是金色的。

非代表:

#import "A"
#import "B"
#import "C"

@synthesize a,b,c;
-(void) increaseProgress {
//incrementProgress
if(self.progress>=1) 
[self.a timeExpired];
[self.b timeExpired];
[self.c timeExpired];
//we don't really know which instance should be messaged
}

重点是,不使用委托会导致代码复杂,通过使用委托,您可以获得更多可重用的组件。计时器不需要知道游戏模式,它只是试图告诉它已经过期了。

© www.soinside.com 2019 - 2024. All rights reserved.