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

当前回答

这么多答案! 尽我所能。呵呵。

首先,你可以使用一个具体的基类和派生类。在这种情况下,你将不得不在基类中为Prepare方法做一个空的或无用的实现,同时使这个方法为虚的,然后派生类将为自己重写这个Prepare方法。在这种情况下,在基类中实现Prepare是无用的。

选择使用接口的原因是必须定义契约,而不是实现。

有一个IPizza类型,它提供了一个功能来准备。这是合同。它是如何准备的是实现,这不是你的把关。这是各种Pizza实现的责任。 这里首选接口或抽象类而不是具体基类,因为您必须创建一个抽象,即Prepare方法。不能在具体基类中创建抽象方法。

现在你可能会说,为什么不用抽象类呢?

所以,当你需要实现100%的抽象时,你需要使用接口。但是当你需要一些抽象和具体的实现时,选择抽象类。它的意思。

例子:假设你所有的披萨都有底料,底料的准备过程是相同的。然而,所有披萨的种类和配料都有所不同。在这种情况下,您可以使用一个抽象方法Prepare和一个具体方法PreparePizzaBase创建一个抽象类。

public abstract class Pizza{
    // concrete method which is common to all pizzas.
    public PizzaBase PreparePizzaBase(){
        // code for pizza base preparation.
    }
    public abstract void Prepare();
}

public class DeluxePizza: Pizza{
    public void Prepare(){
        var base=PreparePizzaBase();
        // prepare deluxe pizza on pizza base.
    }
}

其他回答

在Python中没有鸭子类型的情况下,c#依赖接口来提供抽象。如果类的依赖项都是具体类型,则不能传入任何其他使用类型的接口,可以传入实现该接口的任何类型。

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

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

public void Order();

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

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

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

类比简单解释

无接口(例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。焊工、上釉工、瓦工等)可以完成一些工作。

总结

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

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

什么?

接口基本上是一个契约,所有实现接口的类都应该遵循这个契约。它们看起来像一个类,但没有实现。

在c#中,接口名称的约定是由前缀“I”定义的,所以如果你想要一个名为shapes的接口,你可以将它声明为IShapes

为什么?

提高代码的可重用性

假设你想画圆,三角形。 你可以把它们组合在一起,称为形状,并有方法来绘制圆形和三角形 但有具体的实现将是一个坏主意,因为明天你可能会决定有2个形状矩形和正方形。现在,当您添加它们时,很可能会破坏代码的其他部分。

使用Interface,您可以将不同的实现与契约隔离开来


现场场景第一天

你被要求创建一个应用程序来绘制圆形和三角形

interface IShapes
{
   void DrawShape();
   
 }

class Circle : IShapes
{
    
    public void DrawShape()
    {
        Console.WriteLine("Implementation to Draw a Circle");
    }
}

Class Triangle: IShapes
{
     public void DrawShape()
    {
        Console.WriteLine("Implementation to draw a Triangle");
    }
}
static void Main()
{
     List <IShapes> shapes = new List<IShapes>();
        shapes.Add(new Circle());
        shapes.Add(new Triangle());

        foreach(var shape in shapes)
        {
            shape.DrawShape();
        }
}

现场场景第二天

如果你被要求添加Square和Rectangle,你所要做的就是在Square: IShapes类中创建它的实现,并在Main中添加到列表形状。添加(新广场());

I share your sense that Interfaces are not necessary. Here is a quote from Cwalina pg 80 Framework Design Guidelines "I often here people saying that interfaces specify contracts. I believe this a dangerous myth. Interfaces by themselves do not specify much. ..." He and co-author Abrams managed 3 releases of .Net for Microsoft. He goes on to say that the 'contract' is "expressed" in an implementation of the class. IMHO watching this for decades, there were many people warning Microsoft that taking the engineering paradigm to the max in OLE/COM might seem good but its usefulness is more directly to hardware. Especially in a big way in the 80s and 90s getting interoperating standards codified. In our TCP/IP Internet world there is little appreciation of the hardware and software gymnastics we would jump through to get solutions 'wired up' between and among mainframes, minicomputers, and microprocessors of which PCs were just a small minority. So coding to interfaces and their protocols made computing work. And interfaces ruled. But what does solving making X.25 work with your application have in common with posting recipes for the holidays? I have been coding C++ and C# for many years and I never created one once.