我真的不明白接口存在的原因。据我所知,这是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
    }
}

当前回答

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

以可视化控件为例,在。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 ....
}

其他回答

接口用于驱动一致性,以一种松散耦合的方式,这使得它不同于紧密耦合的抽象类。这就是为什么它通常也被定义为合同。实现接口的任何类都必须遵守接口定义的“规则/语法”,并且其中没有具体的元素。

我将给出一个下图所支持的例子。

Imagine in a factory there are 3 types of machines.A rectangle machine,a triangle machine and a polygon machine.Times are competitive and you want to streamline operator training.You just want to train them in one methodology of starting and stopping machines so you have a green start button and red stop button.So now across 3 different machines you have a consistent way of starting and stopping 3 different types of machines.Now imagine these machines are classes and the classes need to have start and stop methods,how you going to drive consistency across these classes which can be very different? Interface is the answer.

一个简单的例子来帮助你可视化,有人可能会问为什么不用抽象类呢?有了接口,对象不必直接相关或继承,你仍然可以在不同的类之间保持一致性。

public interface IMachine
{
    bool Start();
    bool Stop();
}

public class Car : IMachine
{
    public bool Start()
    {
        Console.WriteLine("Car started");
        return true;
    }

    public bool Stop()
    {
        Console.WriteLine("Car stopped");
        return false;
    }
}

public class Tank : IMachine
{
    public bool Start()
    {
        Console.WriteLine("Tank started");
        return true;
    }

    public bool Stop()
    {
        Console.WriteLine("Tank stopped");
        return false;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var car = new Car();
        car.Start();
        car.Stop();

        var tank = new Tank();
        tank.Start();
        tank.Stop();

    }
}

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

以可视化控件为例,在。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 ....
}

To me an advantage/benefit of an interface is that it is more flexible than an abstract class. Since you can only inherit 1 abstract class but you can implement multiple interfaces, changes to a system that inherits an abstract class in many places becomes problematic. If it is inherited in 100 places, a change requires changes to all 100. But, with the interface, you can place the new change in a new interface and just use that interface where its needed (Interface Seq. from SOLID). Additionally, the memory usage seems like it would be less with the interface as an object in the interface example is used just once in memory despite how many places implement the interface.

下面是一个矩形对象的接口:

interface IRectangular
{
    Int32 Width();
    Int32 Height();
}

它所要求的是实现访问对象宽度和高度的方法。

现在让我们定义一个方法,它可以作用于任何irectangle对象:

static class Utils
{
    public static Int32 Area(IRectangular rect)
    {
        return rect.Width() * rect.Height();
    }
}

这将返回任意矩形物体的面积。

让我们实现一个矩形的类SwimmingPool:

class SwimmingPool : IRectangular
{
    int width;
    int height;

    public SwimmingPool(int w, int h)
    { width = w; height = h; }

    public int Width() { return width; }
    public int Height() { return height; }
}

另一个类House也是矩形的:

class House : IRectangular
{
    int width;
    int height;

    public House(int w, int h)
    { width = w; height = h; }

    public int Width() { return width; }
    public int Height() { return height; }
}

鉴于此,你可以在房屋或游泳池上调用Area方法:

var house = new House(2, 3);

var pool = new SwimmingPool(3, 4);

Console.WriteLine(Utils.Area(house));
Console.WriteLine(Utils.Area(pool));

通过这种方式,您的类可以从任意数量的接口“继承”行为(静态方法)。

我在这个页面上搜索了“合成”这个词,但一次也没看到。这个答案是对前面提到的答案的补充。

在面向对象项目中使用接口的一个绝对重要的原因是,它们允许你更倾向于组合而不是继承。通过实现接口,您可以将您的实现与应用于它们的各种算法解耦。

德里克·巴纳斯(Derek Banas)的“装饰图案”教程(有趣的是,它也以披萨为例)是一个有价值的插图:

https://www.youtube.com/watch?v=j40kRwSm4VE