接口和类之间的区别是什么? 当我可以直接在类中实现方法时,为什么我应该使用接口?

我知道这是一个非常基本的问题,但是一位面试官用一种非常狡猾的方式问了我一个问题,我很无奈:

我只知道接口的材料或理论定义,并且在我参与的许多项目中也实现了它。但我真的不明白为什么这个有用。

我也不明白一件事情在接口。例如,我们使用

conn.Dispose(); in finally block. But I don't see that class is implementing or inheriting IDisposable interface (SqlConnection) class I mean. I am wondering how I can just call the method name. Also in the same thing, I am not understanding how Dispose method works as because, we need to implement the function body with our own implementation for all interface methods. So how Interfaces are accepted or named as contracts? These questions kept on rolling in my mind till now and frankly I never saw any good thread that would explain my questions in a way that I can understand.

MSDN 像往常一样看起来非常吓人,没有一条线是明确的(各位,请原谅那些进入高级别开发的人,我强烈地感觉到任何代码或文章都应该到达任何看到它的人的头脑中,因此就像许多其他人说的,MSDN 是没有用的)。

面试官说:

他有5个方法,他很乐意直接在类中实现它,但是如果你必须选择抽象类或接口,你会选择哪一个,为什么?我确实回答了他所有的东西,我在各种博客上看到说优点和缺点都抽象类和接口,但他不相信,他正在试图理解“为什么接口”一般。“为什么抽象类”一般情况下,即使我只能实现相同的方法一次,而不会改变它。

我看不到在网络的任何地方,我可以得到一篇文章,将解释我清楚的接口及其功能。我是许多程序员中的一员,他们仍然不了解接口(我知道我所使用的理论和方法) ,但是对我清楚地理解它并不满意。

84200 次浏览

接口允许类设计器为最终用户清楚地显示可用的方法。它们也是多态性的一个组成部分。

C # 没有 Duck 类型——仅仅因为您知道某个方法是在一组具体类中实现的,并不意味着您可以对它们进行相同的处理,以调用该方法。实现一个接口允许您将实现该接口的所有类视为同一类型的事物,这与该接口定义的内容有关。

我不会将接口的定义发布到抽象类中,因为我认为你们非常清楚这个理论,我假设你们知道 SOLID 原理,所以让我们来实践一下。

正如您所知道的,接口不能有任何代码,所以缺点是很容易理解的。

如果您需要初始化类的属性,提供一个构造函数,或者您希望提供实现的一部分,那么抽象类将非常适合于不允许您这样做的接口。

因此,当您需要向客户机提供构造函数或任何代码来继承/扩展您的类时,通常应该更喜欢使用抽象类而不是接口

您只能从一个抽象类继承。您可以从多个接口继承。这决定了我在大多数情况下使用什么。

抽象类的优点是您可以有一个基实现。但是,在 IDisposable 的情况下,缺省实现是无用的,因为基类不知道如何正确地清理这些内容。因此,一个接口会更合适。

接口 是实现者必须遵守的契约。Abstract classes允许契约加上共享实现——这是接口所不能具有的。类可以实现和继承多个接口。类只能扩展单个抽象类。

为什么是界面

  • 您没有默认的或共享的代码实现
  • 您希望共享数据契约(Web 服务、 SOA)
  • 对于每个接口实现者(ABC0 has ABC1 and OracleCommand which implement the interface in specific ways) ,都有不同的实现
  • 你想要 支援多重继承

为什么抽象

With an interface you can do the following:

1) Create segregated interfaces which offer differing cuts of your implementation, allowing for a more cohesive interface.

2)允许在接口之间使用多个具有相同名称的方法,因为没有冲突的实现,只有一个签名。

3) You can version and hive off your interface independantly of your implementation, ensuring a contract is met.

4)你的代码可以依赖于抽象而不是具体,允许智能依赖注入,包括注入测试模拟等。

我相信还有更多的原因,这只是其中的一小部分。

一个抽象类允许你有一个部分具体的基础来工作,这不同于一个接口,但是有它自己的特性,比如使用模板方法创建部分实现的能力。

抽象类和接口都是契约。

合同的概念是你指定一些行为。如果你说你已经实施了,你就已经同意了合同。

抽象而非接口的选择是。

抽象类的任何非抽象后代都将实现该契约。

VS

Any class that implements the interface will implement the contract.

因此,当您希望指定所有子代都必须实现的某些行为时,可以使用抽象,并保存自己定义的单独接口,但是现在满足这个有效聚合契约的所有内容都必须是子代。

当您想要创建类似的东西时,接口是非常优秀的:

using System;


namespace MyInterfaceExample
{
public interface IMyLogInterface
{
//I want to have a specific method that I'll use in MyLogClass
void WriteLog();
}


public class MyClass : IMyLogInterface
{


public void WriteLog()
{
Console.Write("MyClass was Logged");
}
}


public class MyOtherClass : IMyLogInterface
{


public void WriteLog()
{
Console.Write("MyOtherClass was Logged");
Console.Write("And I Logged it different, than MyClass");
}
}


public class MyLogClass
{
//I created a WriteLog method where I can pass as a parameter any object that implements IMyLogInterface.
public static void WriteLog(IMyLogInterface myLogObject)
{
myLogObject.WriteLog(); //So I can use WriteLog here.
}
}


public class MyMainClass
{
public void DoSomething()
{
MyClass aClass = new MyClass();
MyOtherClass otherClass = new MyOtherClass();


MyLogClass.WriteLog(aClass);//MyClass can log, and have his own implementation
MyLogClass.WriteLog(otherClass); //As MyOtherClass also have his own implementation on how to log.
}
}
}

在我的例子中,我可以是一个编写 MyLogClass的开发人员,而其他开发人员可以创建他们的类,当他们想要记录日志时,他们实现接口 IMyLogInterface。就像他们问我在 MyLogClass中使用 WriteLog()方法需要实现什么一样。他们将在界面中找到答案。

抽象类是为相关实体创建的,而接口可以用于不相关的实体。

例如,如果我有两个实体说,动物和人类,然后我将去接口,如果我必须去详细说,老虎,狮子和想与动物,然后将选择动物抽象类。.

会看起来像下面

   Interface
____|____
|        |
Animal   Human






Animal (Abstract class)
__|___
|      |
Tiger   Lion

一句话-因为 多态性

如果你“程序到一个接口,而不是一个实现”比你可以注入不同的对象共享相同的接口(类型)到方法作为一个参数。这样,方法代码就不会与其他类的任何实现耦合,这意味着它总是打开以处理同一接口中新创建的对象。(开/关原则)

  • 看看依赖注入,一定要读 gOF 的 abc 0。

我相信在提出这个问题时已经有很多人流血了,很多人试图通过解释没有一个正常人能够理解的类似机器人的术语来解决这个问题。

首先。要学习为什么界面和为什么抽象,你需要学习它们的用途。我个人在申请工厂课程时学到了这两点。你会发现一个很好的教程 on this link

Now let's dig-in base on the link I already gave.

您有 Vehicle类,可能会根据用户的要求而改变(如添加 卡车Tank飞机

public class clsBike:IChoice
{
#region IChoice Members
public string Buy()
{
return ("You choose Bike");
}
#endregion
}

还有

public class clsCar:IChoice
{
#region IChoice Members
public string Buy()
{
return ("You choose Car");
}
#endregion
}

两者都有契约 IChoice,只是说我的类应该有买方法

public interface IChoice
{
string Buy();
}

现在,您可以看到,该接口只强制执行方法 Buy(),但是让继承的类决定在实现它时要做什么。这就是接口的局限性,使用纯接口,您可能最终会重复一些我们可以使用抽象实现的任务。在我们的例子中,比如说,购买每辆车都有折扣。

public abstract class Choice
{
public abstract string Discount { get; }
public abstract string Type { get; }
public string Buy()
{
return "You buy" + Type + " with " + Discount;
}
public class clsBike: Choice
{
public abstract string Discount { get { return "10% Discount Off"; } }
public abstract string Type { get { return "Bike"; } }
}


public class clsCar:Choice
{
public abstract string Discount { get { return " $15K Less"; } }
public abstract string Type { get { return "Car"; } }
}

现在使用 Factory Class,您可以实现同样的功能,但是在使用抽象时,您让基类执行 Buy()方法。

总结: 接口契约让继承类执行 而 Abstract class契约可以初始化实现(可以由 Heritage 类重写)

我使用接口的一个原因是它增加了代码的灵活性。假设我们得到了一个以 Account 类型的对象作为参数的方法,比如:

public void DoSomething(Account account) {
// Do awesome stuff here.
}

The problem with this, is that the method parameter is fixed towards an implementation of an account. This is fine if you would never need any other type of account. Take this example, which instead uses an account interface as parameter.

public void DoSomething(IAccount account) {
// Do awesome stuff here.
}

This solution is not fixed towards an implementation, which means that I can pass it a SuperSavingsAccount or a ExclusiveAccount (both implementing the IAccount interface) and get different behavior for each implemented account.

enter image description here

所以在这个例子中,PowerSocket 不知道关于其他对象的任何信息。这些对象都依赖于 PowerSocket 提供的 Power,因此它们实现了 IPowerPlug,这样它们就可以连接到它。

接口之所以有用,是因为它们提供了契约,对象可以使用这些契约一起工作,而无需了解对方的任何其他信息。

这是一个简单的例子:

ArrayList都实现了接口 IList。下面我们有一个 string[]和一个 List<string>,并且通过使用 伊利斯特只用一种方法操作它们:

string[] myArray = { "zero", "one", "two", "three", "four"};
List<string> myList = new List<string>{ "zero", "one", "two", "three"};


//a methode that manipulates both of our collections with IList
static void CheckForDigit(IList collection, string digit)
{
Console.Write(collection.Contains(digit));  //checks if the collection has a specific digit
Console.Write("----");
Console.WriteLine(collection.ToString()); //writes the type of collection
}


static void Main()
{
CheckForDigit(myArray, "one");   //True----System.String[]
CheckForDigit(myList, "one");   //True----System.Collections.Generic.List`1[System.String]






//Another test:


CheckForDigit(myArray, "four");   //True----System.String[]
CheckForDigit(myList, "four");   //false----System.Collections.Generic.List`1[System.String]
}

Interfaces are to make an abstraction (an archetype) of the abstraction (the classes) of the reality (the objects).

接口指定契约条款,而不提供类提供的实现。

接口是规格说明:

  • 接口是设计时的工件,用于指定概念的固定行为,因为它是单独的和静态的。

  • 类是实现时的工件,用于在现实交互和移动时指定现实的移动结构。

什么是接口?

当你观察一只猫的时候,你可以说它是一种有四个爪子、一个头、一个鼻子、一条尾巴和一根头发的动物。你可以看到他可以走路,跑步,吃饭和喵喵叫。诸如此类。

您刚刚定义了一个包含其属性和操作的接口。因此,您没有定义任何操作方式,而只定义了特性和功能,而不知道事情是如何运作的: 您具有已定义的功能和区别。

As such it is not really yet a class even though in UML we call this a class in a class diagram because we can define privates and protected members to begin having a deep view of the artifact. Do not be confused here because in UML an interface is a slightly different thing that an interface in C#: it is like a partial access point to the abstraction atom. As such we said that a class can implements multiple interfaces. As such it is the same thing, but not, because interfaces in C# are both used to abstract the abstraction and to limit this abstraction as an access point. It's two different uses. Thus a class in UML represents a full coupling interface to a programming class, whereas an UML interface represents a decoupling interface of a section of a programming class. Indeed, the class diagram in UML does not take care of the implementation and all its artifacts are at the programming interface level. While we map UML classes to programming classes, it is a transposition of abstract abstraction into concrete abstraction. There is a subtlety that explains the dichotomy between the field of design and the field of programming. So a class in UML is a programming class from the point of view of a programming interface while considering inner hidden things.

Interfaces also allow to simulate multiple inheritance when not available in an awkward way. For example, the cat class will implement the cat interface that derives itself from the animal interface. This cat class will also implement these interfaces: walk, run, eat and make a sound. This compensates for the absence of multiple inheritance at the class level, but each time you need to reimplement everything and you can not factor the reality at best like the reality itself do it.

为了理解这一点,我们可以参考 Pascal Object 编码,其中在单元中定义接口和实现部分。在接口中定义类型,在实现中实现类型:

unit UnitName;


interface


type
TheClass = class
public
procedure TheMethod;
end;


implementation


class procedure TheClass.TheMethod;
begin
end;

在这里,接口部分与 UML 类设计相匹配,而接口类型是其他事情。

因此,在我们的业务中,我们用一个词 接口来指代两个不同但相似的事物,这是一个混淆的来源。

例如,在 C # 中,编程接口允许补偿开放类型上真正泛型多态性的缺失,而不能真正实现目标,因为您失去了强类型的能力。

毕竟,接口对于允许不兼容的系统进行通信是必要的,而不必担心内存中对象的实现和管理,就像(分布式)公共对象模型中引入的那样。

什么是班级?

After defining a reduction of the reality from an external point of view, you can then describe it from an inside perspective: this is the class where you define data processing and message management to allow the reality you have encapsulated to come to life and interact thanks to objects using instances.

所以在 UML 中,你实现了机器车轮的分形浸入,你描述了状态、交互等等,以便能够实现你想要处理的现实片段的抽象。

因此,从编译器的角度来看,抽象类在某种程度上等同于接口。

More information

议定书(面向对象程序设计)

C# - Interfaces

C #-课程

让我告诉你什么是飞行烤面包机。

flying toaster

当然,在许多情况下,您可以构建一个工作的软件系统,而不需要声明或实现任何接口: 任何面向对象的软件设计都可以只使用类来实现。

同样,任何软件系统也可以用汇编语言实现,或者用机器代码实现更好。我们之所以使用抽象机制,是因为它们使事情变得更容易。接口就是这样一种抽象机制。

所以,碰巧有一些非常重要的面向对象设计,如果使用接口,实现起来要容易得多,在这些情况下,接口实际上是必要的。

这些非平凡的设计与多重继承有关,在其“真正的”形式中,当一个类不仅从一个基类继承,而且从两个或更多的基类继承。这种真正的形式在 C # 中是不可能的,但是在像 C # 和 Java 这样的语言出现之前,统治语言是 C + + ,它完全支持真正的多重继承。不幸的是,真正的多重继承并不是一个好主意,因为它极大地复杂化了语言的设计,同时也引起了各种各样的问题,例如著名的“钻石问题”。(见 “多重继承到底有什么问题?”)

因此,如果有人想要构建一个“飞行烤面包机”类,他们将继承一些现有的“烤面包机”类和一些现有的“飞行”类。他们可能遇到的问题是,烤面包机的电源可能是墙上的插座,而飞行机甲的电源可能是鸽子的食物,产生的新职业要么两者兼备,要么不知道是哪一个。(钻石问题)

像 C # 和 Java 这样的语言的创建者决定不允许真正的多重继承,以保持语言的简单性,避免像钻石问题这样的陷阱。然而,某种形式的多重继承仍然是必要的(或者至少是非常可取的) ,所以在这些语言中,他们引入了接口作为一种支持较小形式的多重继承的手段,同时避免了真正的多重继承的问题和复杂性。

In this lesser form of multiple inheritance, you are not allowed to have a class which inherits from more than one base class, but you can at least inherit from one or more interfaces. So, if you want to build a flying toaster, you cannot inherit both from some existing toaster class and some existing flying class, but what you can do is inherit from an existing toaster class and then also expose a flying interface which you implement yourself, possibly using whatever means you have already inherited from toaster.

因此,除非你觉得有必要创建一个聚合了两个不同的和不相关的功能集的类,否则你不会需要任何形式的多重继承,所以你不需要声明或实现任何接口。