ruby 中的代表从 Cocoa 开发人员背景中解释

delegates in ruby explained from a Cocoa developer background

我真的希望有人能回答这个问题。我想我绝对不是唯一对此感到困惑的人,我找不到任何可以清楚地解释这个概念的东西。

我对委托模式的理解来源于对Cocoa框架的研究。对我来说,Cocoa 的实现非常清晰。但是我很难在 Ruby 中理解它(标准库的 DelegatorSimpleDelegatorActiveSupportDelegate)。这对我来说没什么意义。主要是因为一个是类型安全的,另一个是鸭子类型。您已经可以看到我的观点,但请允许我展开...这是我对如何在 Cocoa:

中使用委托模式的总结

我们的“成分”是:2 classes、AB 以及一个 protocol,即 Cocoa 用于预定义用于委派的一组方法。

模式的实现基本如下:

  1. A 定义委托给 B.

    的方法集
  2. B 的委托设置为 A

    => B 现在可以像这样调用委托方法:@delegate.send(a_delegated_method)

我没有把 Ruby 与鸭子类型联系在一起的事实,因此您可以将任何方法调用发送到任何对象,对吗?所以使用我刚才解释的模式,只要这两个对象在同一个域中,你就可以在 A @b.send(:a_delegated_method) 中说,反之亦然,在 B @a.send(:another_delegated_method) 中。

难道Ruby中有委托的地方就是定义委托方法的地方?意思是我们从 class A 发送到 属性 @b (@b(:delegated_method)) 一个在 A 本身定义的 :delegated_method

希望这不会太混乱。我自己很困惑为什么委托甚至存在于鸭子打字语言中,以及 DelegatorSimpleDelegatorActiveSupportDelegate.

之间有什么区别

我不清楚您是否了解委派在 Cocoa 中的工作原理。 Cocoa 中委托模式的常见变体确实涉及协议,但这只是让编译器安静下来的一种方式。

所以让我们先谈谈让编译器安静下来。您不能将 woohoo 消息发送到 Objective-C 中的对象,除非以下两个条件之一为真:

  • 编译器有理由相信此对象可能会响应 woohoo 消息。

  • 让编译器暂停判断

如今,通常使用第一种方法 - 这就是协议的用途。但情况并非总是如此。过去,授权主要依赖于 非正式协议 。 Cocoa 中仍然存在非正式协议。这个想法是要么该方法通过类别注入到 NSObject 中,要么您小心地将对象键入 id 以便它可以发送任何消息。

现在让我们谈谈活力。不再使用非正式协议的原因是引入了允许协议声明可选成员的功能。但是活力还是需要的!我们可能会以某种方式满足编译器,但在运行时,我们必须确保将特定消息发送到一定的对象。您的应用委托可能采用 UIApplicationDelegate,但 Cocoa 不会向它发送 applicationDidBecomeActive: 消息,除非您的应用委托 class 实现 applicationDidBecomeActive: - 如果是这样,你会崩溃,那不是很好。

此外,如果您可以通过编译器,您可以在 Objective-C 中执行比这更动态的委托,如此处解释:

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html

我们的想法是在运行时直接向对象发送消息!如果对象 A 无法处理的消息到达,它可以查看对象 B 是否处理它。如果是,它会将消息传递给对象 B。所以我们可能不会崩溃!我在我的一个应用程序中使用了这种方法:

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.originalDataSource respondsToSelector: aSelector])
        return self.originalDataSource;
    return [super forwardingTargetForSelector:aSelector];
}

在该代码中,我是说如果消息到达但我无法处理它,我应该尝试将它发送到另一个对象,称为 self.originalDataSource

如果您考虑一下,这几乎与 Ruby 授权相同。我有一个辅助对象,我无法处理的消息会传递给它。

此模式的另一个常见用途是包装 Cocoa 集合。你不能 subclass,比如 NSArray,因为它是一个 class 集群,所以正确的方法是包装它。然后,您只需将所有内容转发给 NSArray,很快,您就被鸭子类型化为 NSArray!就您的方法而言,您看起来像一个 NSArray。然后你引入了一些行为上的差异,现在你被鸭子类型化为一个自定义的 NSArray。