我真的不明白接口存在的原因。据我所知,这是c#中不存在的多继承的一种工作(至少我是这么被告知的)。

我所看到的是,您预定义了一些成员和函数,然后必须在类中再次重新定义它们。从而使接口成为冗余。它只是感觉像句法……嗯,垃圾对我来说(请没有冒犯的意思。Junk是指无用的东西)。

在下面的例子中,我将创建一个名为Pizza的基类,而不是一个接口。

简单示例(取自不同的堆栈溢出贡献)

public interface IPizza
{
    public void Order();
}

public class PepperoniPizza : IPizza
{
    public void Order()
    {
        //Order Pepperoni pizza
    }
}

public class HawaiiPizza : IPizza
{
    public void Order()
    {
        //Order HawaiiPizza
    }
}

当前回答

接口实际上是实现类必须遵循的契约,它实际上是我所知道的几乎所有设计模式的基础。

在您的示例中,创建接口是因为这样就保证实现了比萨饼接口的is A Pizza

public void Order();

在你提到的代码之后,你可以这样写:

public void orderMyPizza(IPizza myPizza) {
//This will always work, because everyone MUST implement order
      myPizza.order();
}

这样您使用的是多态性,您所关心的只是对象对order()做出响应。

其他回答

Pizza示例很糟糕,因为您应该使用一个处理排序的抽象类,而pizzas应该重写Pizza类型。

当您有一个共享属性,但是您的类从不同的地方继承,或者当您没有任何可以使用的公共代码时,您可以使用接口。例如,这是用过的东西,可以被处置为IDisposable,你知道它会被处置,你只是不知道当它被处置时会发生什么。

接口只是一个契约,它告诉你一个对象可以做一些事情,什么样的参数和期望什么样的返回类型。

考虑一下不控制或不拥有基类的情况。

以可视化控件为例,在。net for Winforms中,它们都继承自。net框架中完全定义的基类Control。

让我们假设您从事创建自定义控件的业务。你想要建立新的按钮,文本框,列表视图,网格,等等,你希望他们都有特定的功能独特的控件集。

例如,你可能想要一种通用的方法来处理主题,或者一种通用的方法来处理本地化。

在这种情况下,你不能“只创建一个基类”,因为如果你这样做,你必须重新实现所有与控件相关的东西。

相反,您将从按钮,TextBox, ListView, GridView等下降,并添加您的代码。

但这就产生了一个问题,你现在如何识别哪些控件是“你的”,你如何构建一些代码来表明“对于窗体上所有属于我的控件,将主题设置为X”。

输入接口。

接口是一种查看对象、确定对象是否遵守某种约定的方法。

您可以创建“YourButton”,从Button向下延伸,并添加对所需的所有接口的支持。

这将允许您编写如下代码:

foreach (Control ctrl in Controls)
{
    if (ctrl is IMyThemableControl)
        ((IMyThemableControl)ctrl).SetTheme(newTheme);
}

如果没有接口,这是不可能的,相反,你必须写这样的代码:

foreach (Control ctrl in Controls)
{
    if (ctrl is MyThemableButton)
        ((MyThemableButton)ctrl).SetTheme(newTheme);
    else if (ctrl is MyThemableTextBox)
        ((MyThemableTextBox)ctrl).SetTheme(newTheme);
    else if (ctrl is MyThemableGridView)
        ((MyThemableGridView)ctrl).SetTheme(newTheme);
    else ....
}

上面的例子没有多大意义。你可以使用类来完成上面所有的例子(如果你想让它只表现为一个契约,那么它就是抽象类):

public abstract class Food {
    public abstract void Prepare();
}

public class Pizza : Food  {
    public override void Prepare() { /* Prepare pizza */ }
}

public class Burger : Food  {
    public override void Prepare() { /* Prepare Burger */ }
}

你会得到和界面相同的行为。您可以创建一个List<Food>,并迭代w/o知道什么类位于顶部。

更合适的例子是多重继承:

public abstract class MenuItem {
    public string Name { get; set; }
    public abstract void BringToTable();
}

// Notice Soda only inherits from MenuItem
public class Soda : MenuItem {
    public override void BringToTable() { /* Bring soda to table */ }
}


// All food needs to be cooked (real food) so we add this
// feature to all food menu items
public interface IFood {
    void Cook();
}

public class Pizza : MenuItem, IFood {
    public override void BringToTable() { /* Bring pizza to table */ }
    public void Cook() { /* Cook Pizza */ }
}

public class Burger : MenuItem, IFood {
    public override void BringToTable() { /* Bring burger to table */ }
    public void Cook() { /* Cook Burger */ }
}

然后你可以把它们都作为菜单项使用,而不用关心它们如何处理每个方法调用。

public class Waiter {
    public void TakeOrder(IEnumerable<MenuItem> order) 
    {
        // Cook first
        // (all except soda because soda is not IFood)
        foreach (var food in order.OfType<IFood>())
            food.Cook();

        // Bring them all to the table
        // (everything, including soda, pizza and burger because they're all menu items)
        foreach (var menuItem in order)
            menuItem.BringToTable();
    }
}

接口的主要目的是在您和实现该接口的任何其他类之间建立契约,使您的代码解耦并允许可扩展性。

类比简单解释

无接口(例1):

无接口(例2):

有接口:

需要解决的问题:多态性的目的是什么?

比方说,我是一个建筑工地的领班。我不知道哪个商人会走进来。但我告诉他们该怎么做。

如果是木匠,我会说:搭建木质脚手架。 如果是管道工,我会说:安装管道 如果是人民党政府官员,我说,三袋现金,先生。

上述方法的问题在于:(1)我必须知道谁会走进那扇门,并且根据是谁,我必须告诉他们该做什么。这通常会使代码更难维护或更容易出错。

知道该做什么的含义:

This means if the carpenter's code changes from: BuildScaffolding() to BuildScaffold() (i.e. a slight name change) then I will have to also change the calling class (i.e. the Foreperson class) as well - you'll have to make two changes to the code instead of (basically) just one. With polymorphism you (basically) only need to make one change to achieve the same result. Secondly you won't have to constantly ask: who are you? ok do this...who are you? ok do that.....polymorphism - it DRYs that code, and is very effective in certain situations: with polymorphism you can easily add additional classes of tradespeople without changing any existing code. (i.e. the second of the SOLID design principles: Open-close principle).

解决方案

想象一下这样一个场景:无论谁走进来,我都可以说:“Work()”,他们做着自己擅长的工作:管道工处理管道,电工处理电线,官僚可能专门负责受贿,为其他人做双倍的工作。

这种方法的好处是:(i)我不需要确切地知道谁会走进那扇门——我只需要知道他们是一种手工工人,他们会工作,其次,(ii)我不需要知道任何关于特定行业的信息。手工工人会处理的。

所以不要这样:

if(electrician) then  electrician.FixCablesAndElectricity() 

if(plumber) then plumber.IncreaseWaterPressureAndFixLeaks() 

if(keralaCustoms) then keralaCustoms.askForBribes() 

我可以这样做:

ITradesman tradie = Tradesman.Factory(); // in reality i know it's a plumber, but in the real world you won't know who's on the other side of the tradie assignment.

tradie.Work(); // and then tradie will do the work of a plumber, or electrician etc. depending on what type of tradesman he is. The foreman doesn't need to know anything, apart from telling the anonymous tradie to get to Work()!!

有什么好处?

这样做的好处是,如果木匠等特定的工作要求发生了变化,那么领班就不需要改变他的代码——他不需要知道或关心。重要的是木匠知道Work()是什么意思。其次,如果一种新型的建筑工人来到工地上,那么工头不需要知道任何关于贸易的事情——工头所关心的是建筑工人(.e。焊工、上釉工、瓦工等)可以完成一些工作。

总结

界面允许您让人完成分配给他们的工作,而不需要您确切地知道他们是谁或他们可以做什么。这允许您轻松地添加新的(交易)类型,而无需更改现有的代码(从技术上讲,您确实更改了一点点),这是面向对象方法相对于更函数式编程方法的真正好处。

如果你不理解上面的任何内容,或者不清楚,请在评论中提问,我会尽量让答案更好。