【问题标题】:In OOP, what is forwarding and how is it different from delegation?在 OOP 中,什么是转发,它与委托有何不同?
【发布时间】:2011-12-10 14:07:44
【问题描述】:

有人能解释一下转发和委托之间的区别吗?它们看起来很相似,但我一直无法找到一个好的转发定义,所以我不确定我是否真的理解。

【问题讨论】:

  • 不知道为什么这被否决了......这似乎是一个有用的问题,虽然它可以使用更多的细节。不幸的是,我们在这里可能处于 Catch-22 中。我会尽量提供答案,如果我理解正确,提问者可以告诉我。

标签: c++ oop class delegation forwarding


【解决方案1】:

它们的相似之处在于一个对象依赖另一个对象来寻求帮助。鉴于我对 Objective-C 的强烈偏见,以下是我对这两个想法的看法:

代表团:需要做出决定,但我不想做出决定。我会让我的代表来处理。

例如,在 Cocoa 中,NSTableView 使用委托来自定义表的行为。委托提供了一种方法来定制一个对象,方法是让另一个对象(委托)提供定制。继续这个例子,表格视图的委托实现了一个NSTableViewDelegate 接口,表格用来与它的委托对话。

转发:有人刚刚给我发了一条我不明白的消息,但我知道另一个可能实现它的对象。我会将对该消息的调用传递给该对象。

同样,在 Cocoa 中,任何类都可以实现 -forwardInvocation: 方法。如果将消息发送到未实现它的对象,则调用该对象的 -forwardInvocation: 方法,并且该对象可以决定将调用传递给另一个对象。该对象可能是它的委托,或者它可能是一些系统范围的错误处理程序,或其他任何东西。 NSProxy 使用它来实现 all 方法——它只是将调用传递给它的主对象。

请注意,对于转发,没有定义的委托接口;消息只是传递给另一个对象。另一个你看到我称之为转发的地方是当一个对象包含另一个用于实现某个接口的对象时。到该接口的任何消息都只会转发到包含的对象,它会完成所有工作。

【讨论】:

    【解决方案2】:

    转发有点像“通过包含继承”,或“以困难的方式实现继承”。

    典型的实现继承:

    class Base
    {
     public:
        void baseFn() { }
    };
    
    class Derived : public Base
    {
     public:
        void derivedFn() { }
    };
    

    现在,Derived 的一个实例有一个 baseFn() 方法。这是一种在不同类之间共享实现的方式。

    转发看起来像这样:

    class Contained
    {
     public:
        void containedFn() { }
    };
    
    class Thing
    {
     public:
        void thingFn() { }
        void containedFn() { mContained.containedFn(); }
     private:
        Contained mContained;
    };
    

    您也可以使用私有继承来实现它。

    委托是转发的一种特殊情况,其中“要转发的东西”是一个接口本身。

    class Delegate
    {
     public:
        virtual void doDelegateAction() = 0;
    };
    
    class DelegateA : public Delegate
    {
        virtual void doDelegateAction() { }
    };
    
    class DelegateB : public Delegate
    {
        virtual void doDelegateAction() { }
    };
    
    class Thing
    {
     public:
        void Thing (Delegate * delegate) { mDelegate = delegate; }
        void thingFn() { }
        void containedFn() { if (mDelegate) mDelegate->doDelegateAction(); }
     private:
        Delegate * mDelegate; // Note, we don't own this memory, buyer beware.
    };
    

    现在,您可以在运行时换出委托的实现,而在转发时则不能(而且您可能不想这样做,这就是您要这样做的原因)。

    如果这回答了错误的问题,请在评论中告诉我,我会删除答案。

    【讨论】:

    • 那么您是说转发要求类将委托对象包含在类中,但委托可以选择使用在类之外实例化的对象?两者的区别还不是很清楚。
    • @vette982 抱歉,我在上一个示例中遗漏了一个关键点...编辑即将推出。
    • @KerrekSB 啊,你是对的。我将示例更改为 & 因为这更简单。
    • @KerrekSB 决定用 * 代替,以维护委托的运行时替换。
    • @MichaelPrice:哦,我在想你应该说mDelegate = std::move(delegate);,但是好吧:-)
    【解决方案3】:

    我们先定义两个术语:

    • 发件人the object that sends a message/task to another object(the receiver)
    • 接收者the object that receives a message/task from the sender

    forwardingdelegation 之间的区别在于 forwarding the receiver acts in its own context 而在 delegation the receiver acts on the behalf of the sender .

    这是blog post的一个很好的比喻:

    委托和转发都非常相似。一个可能有助于区分它们的隐喻是想象收到一封电子邮件,要求您向有价值的慈善机构捐款。

    • 如果您将电子邮件转发给朋友,而朋友捐款,则朋友捐款并获得了自己的税单。
    • 如果您委派回应您的会计师,会计师将您的钱捐赠给慈善机构,您会收到税单。

    【讨论】:

    • 我认为这个答案有点令人困惑,因为“发送者”和“接收者”的定义在这种情况下可能是模棱两可的。假设类Foo 包含Bar 类型的成员并将消息转发给它。 Foo 既是接收者(它从某个外部对象接收消息)又是发送者(它将消息发送到 Bar)。我假设在这种情况下,“接收者代表发送者行事”的陈述旨在表示“代表Foo”,而不是“代表最初发送消息的对象”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    相关资源
    最近更新 更多