何时使用委托而不是接口?

6
根据这篇文章,它说:

在以下情况下使用委托:

  • 类需要多个方法的实现。

在以下情况下使用接口:

  • 类只需要一种方法的实现。
请问有人能为我解释一下吗?

1
你可以将委托视为只有一个方法的接口。 - Steven
4
我在 MSDN 的文章上留了反馈,建议用词更加清晰明了。 - Marc Gravell
5个回答

6
一个类可能需要多个方法的实现。
public delegate int PerformCalculation(int x, int y);

void SomeMethod()
{
    PerformCalculation PerformCalculation_1 = myDelegateFun_1;
    PerformCalculation PerformCalculation_2 = myDelegateFun_2;
    PerformCalculation_1(5, 3);
    PerformCalculation_2(5, 3);      
}

private int myDelegateFun_1(int x, int y)
{
    return x + y;
}
private int myDelegateFun_2(int x, int y)
{
    return x + y;
}

在上面的例子中,PerformCalculation_1和PerformCalculation_2是PerformCalculation的多个实现。
A class only needs one implementation of the method

 

interface IDimensions 
{
   float Length();
}

class Box : IDimensions 
{
   float Length() 
   {
       return lengthInches;
   }
}

在上面的例子中,只有接口公开的方法的单一实现。

1
委托类型“仅包含方法、委托或事件的签名”——只有一个方法。委托实例还适合于“在实现委托类型的{thing}中完成方法的实现”。 - Marc Gravell
@Marc Gravell,我尝试理解问题陈述并得出了更新的答案。您能否审核一下。 - Adil
谢谢,讲得很清楚。 - Richard

6
那很奇怪而且令人困惑。如果你只需要一个方法的实现,就使用一个方法(或许是虚方法)。正如接口一样,委托的其中一点重要作用是你可以替换多个不同的实现。
如果我必须概括:
委托类型非常像只公开单个方法的接口,委托实例非常像实现该接口的类的实例——只不过有许多编译器的技巧,使其编写变得非常容易,例如x => 2 * x,并且有时不需要实例。
委托还有一些其他有用的技巧,针对事件(多播等),但这听起来与本文的上下文无关。

有点同意,但我想指出接口的实现可以携带状态或更多数据,这些数据可能与(单个)方法的实现相关,即“更多”可能性。通常,某些版本的命令模式仅依赖于Func<TResult>,而其他版本则希望携带更多的方法,接口可能依赖于其他一些接口。 - Natalie Perret

1
在我看来,这与 ICompare/IComparable 很相似。
接口的实现意味着行为内在于实现类中。行为不会根据调用者或调用情况而改变。
委托表示操作不是内在于类中的,而是基于上下文或调用者来定义的。

0

•该接口仅定义了一个方法。 •需要多播功能。 •订阅者需要多次实现该接口。


0

这个措辞似乎有点令人困惑,但可以通过一个例子来说明。假设正在设计一个按钮控件,希望在单击时提供通知。常见的做法是让按钮维护要调用的委托列表。如果一个类希望让按钮在其实例上调用其中一个方法,它可以轻松地构造一个委托,该委托将在该实例上调用该方法。请注意,为此目的使用委托意味着需要为委托构造一个堆对象,除了要调用委托的实例之外。

一种替代方法是定义一个接口INotifyOfButtonClick,其中包含一个方法NotifyOfButtonClick(),并让按钮控件保持INotifyButtonClick列表。当单击按钮时,它会在每个实例上调用NotifyOfButtonClick()。如果一个窗体只有一个使用该接口的按钮,或者所有这样的按钮都使用相同的方法,则窗体可以自己实现INotifyOfButtonClick(),并将自己添加到按钮的订阅列表中,而不必创建一个单独的委托来调用其方法。在这种方法适用的情况下,它比使用委托更有效率。但是,如果一个窗体有两个使用相同接口的按钮,但想要调用不同的方法,那么情况就会变得更加复杂。在这种情况下,窗体需要创建一个新对象,其目的是通过调用对其保持引用的窗体上的某个方法来实现INotifyOfButtonClick()。使用这样的包装对象可能会产生与委托相当的性能,但没有一些编译器辅助委托的功能。

顺便说一下,如果微软能够为每个委托添加一个嵌套接口IInvoke(例如,Action<int>将定义一个接口Action<int>.IInvoke),那么如果接受Action<int>的方法被重写以接受Action<int>.IInvoke,那么只有一个方法将由这些委托调用的对象可以简单地将自己传递给这样的方法。这种功能可以提高闭包的效率。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接