0

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

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

我想:有了委托,你就不用去实例化一个新的整个类了,你可以在类之外设置委托,然后用“委托”调用方法。使用代表来避免无限导入也是一件好事吗?就像classA导入classB一样,如果你实例化类而不是使用委托,classB也会导入classA,它会导致崩溃吗?

当您创建自己的协议/委托时,还有其他好的理由吗?

感谢分享

4

3 回答 3

1

好吧,看一个例子。

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

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

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

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

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

于 2012-08-15T10:40:55.000 回答
1

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

我们来看一个具体的例子: NSTableView的数据源。 NSTableView为 OS X 中的表提供 UI 实现。数据源委托提供了获取数据以填充表的功能。

在我来到 Objective-C 并用 C++ 和 Java 编程之前的过去,我会通过 UI 类和一些受保护的方法来管理数据,这些方法将被子类化以创建不同的表视图,从而实现了一个表视图。

这种方法是完全有效的,但是它将管理数据的功能与显示的功能混为一谈,而且不是很灵活。一旦你说小部件 X 是一个表格视图,它以某种方式访问​​数据,那一切都是一成不变的。如果您希望小部件 X 以不同的方式获取其数据,您必须将这种灵活性构建到 UI 类中,或者销毁它并从不同的子类重新创建它。

另一方面,委托模式允许NSTableView通过简单的分配和重新加载来完全更改其数据源。此外,UI 类不会被数据处理代码污染,数据处理类也不会被 UI 处理代码污染。

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

于 2012-08-15T11:23:33.677 回答
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
}

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

于 2012-08-15T10:31:59.157 回答