接口的意义C#

我想知道Interface的重要用途。 我已经阅读了很多文章,但没有清楚地了解界面的概念。

我写了一个小程序。 我已经定义了接口Itest.Class(Manager)已经实现了Interface.Another class(Employee)还没有实现接口。 但是在类( Employee )的接口中定义了相同的方法( DoSomething() )。 我可以从类对象中调用该方法。 那我为什么要去实现接口呢? 我可以在类中直接实现该方法并调用该方法。 为什么我要在接口中执行额外的步骤,然后按类inheritance接口。 我知道接口支持多重inheritance,但在这个例子中我没有使用多重inheritance。

感谢您的任何想法或意见。

 public interface Itest { void DoSomething(); } public class Manager:Itest { public void DoSomething() { Console.WriteLine("test...."); } } class Employee { public void DoSomething() { Console.WriteLine("test...."); } } class Program { static void Main(string[] args) { Manager m = new Manager(); m.DoSomething(); Employee e = new Employee(); e.DoSomething(); Console.ReadLine(); } } 

接口允许您使用多重inheritance。 在您的示例中,它允许您将Employee或Manager的实例放入同一个变量中,然后在该变量上调用DoSomething ,并将方法调用分派给该变量当前引用的实例。 例如:

 public interface IEmployee { void DoSomething(); } // assume Manager and Employee both implement IEmployee IEmployee ie = new Manager(); ie.DoSomething(); // calls Manager.DoSomething() ie = new Employee(); ie.DoSomething(); // calls Employee.DoSomething() 

如果您没有使用接口,则必须执行以下操作:

 object o; // assign Manager or Employee (or something else!) to o if (o is Manager) ((Manager)o).DoSomething(); else if (o is Employee) ((Employee)o).DoSomething(); 

接口定义了一个契约 ,只要实例实现了该接口,您就不关心它在运行时的实际内容。 您可以让同一个类实现多个接口,然后在这些接口的所有变量中使用该类的实例。 您不能对抽象类使用相同的内容,因为类一次只能inheritance一个类。

我现在使用接口的一个例子是定义一个对象模型 – 我有各种属性的接口( IHasStorageIHasPrivilegesIHasCheezburger ),然后表示具体对象的类实现了适合该类的任何接口。 ‘属性

接口用于抽象(抽象类也用于此,但通常包含一些旨在重用的实现)。

在C#中,它们允许使用多重inheritance,这意味着您可以在一个类中实现许多不同的接口。

如果您有许多不同的接口实现,只要使用接口声明,就可以互相替换它们。

例如:

IAnimal可以由CatDog 。 在其他代码中,您希望调用在接口中声明的Talk方法。 您的代码不必关心它是Cat对象还是Dog对象。 您可以添加DuckHuman而不是更改那段代码。

这在使用模拟对象测试代码时也很有用,因此可以用一个简单的对象替换真实的对象以进行测试。

一些接口用作标记,因此reflection可以轻松地拾取它们(例如, ISerializable接口,将类标记为可序列化)。

实现inheritance模型是“IS A KIND OF”关系,而接口inheritance模型是“CAN BEHAVE LIKE”关系。 许多BCL界面名称以“-able”结尾并代表能够做某事的能力并非巧合。 要演示,请对以下代码进行成像:

 class Person { public string Name{get;set;} public void Walk() {/*code elided*/} } class Employee : Person { public int Id{get;private set;} } 

显然,员工“是一种”人。 所有员工都是人,因此他们都有一个名字,可以走路()。 无论如何使Person或Employee成为抽象的,它并没有改变所有员工都是人的事实。

现在让我们更抽象一点,谈谈作为车辆的概念。 作为车辆的绝对必要条件是它必须能够移动和停止。 你可能包括转向和载客,但我保持非常抽象。

让我们考虑一些作为车辆的东西。 当然是一辆车,但一个人怎么样? 他们可以移动和停止(当我给我的侄子和侄女背驮我也带着乘客!)一把小椅子? 我永远在办公室里徘徊。 我也是一名敏锐的水手,并利用风来加速和减速我的车辆。

你不能使用实现inheritance对这种关系进行建模,因为你有很多不同的东西,“可以像”一样,但不必从同一个基类inheritance。

pogostick(向专业的pogo-ers道歉)是一种玩具,但可以作为一种载体。 并非所有玩具都是车辆。 一个人与汽车没有任何关系,除了它可以作为一辆汽车。

 interface IVehicle { void Move(); void Stop(); } class Toy{} class PogoStick : Toy, IVehicle { public void Move(){ /* boing boing */} public void Stop(){ /* fall over */} } class Car: IVehicle { public void Move(){ /* vroom vroom */} public void Stop(){ /*  */} } class Person : IVehicle { public string Name{get;set;} public void Walk() {/*code elided*/} void IVehicle.Move() { Walk(); } void IVehicle.Stop() { /*whatever!*/} } class Program { static void Main() { IVehicle[] vehicles = new IVehicle[3]; vehicles[0] = new PogoStick(); vehicles[1] = new Car(); vehicles[2] = new Employee(); //implements IVehicle because it IS A KIND OF Person vehicles.ForEach(v => v.Move()); //it's worth pointing out that vehicles[2].Stop(); //works fine, but Person p = new Person(); p.Move(); //won't, as I explicitly implemented the interface, meaning I can only get at the //methods via a reference to the interface, not to the implementing class. } } 

要使用.NET本身的一个例子,地球上的字符串与List有什么共同之处? 不是很多,除了我可以“预告”他们两个:

 class Demo { static void Main() { string s = "Hello!"; List payroll = new List(); for each (var item in s) { Console.WriteLine(item); } for each (var item in payroll) { Console.WriteLine(item); } } 

string和List的公共基类是object,但并非所有对象都是“for-each-able”,因此必须要有其他内容。 即他们都实现了IEnumerable接口(那就是那个!)!

将接口添加到Employee时,两个类通过该接口变得兼容:

 public class Manager:Itest { ... } class Employee:Itest { ... } static void ShowSomething(Itest test) { test.DoSomething(); } static void Main(string[] args) { Manager m = new Manager(); Employee e = new Employee(); ShowSomething(m); ShowSomething(e); } 

看看BCL如何使用界面,开始查找IDisposable,ISerializable,IComprable和IEnumerable

接口的inheritance使您可以在不破坏代码的情况下使用其他类或对象更改实现。 接口意味着您与代码的客户签订合同,您将提供一些function,并且他们不必知道要为此调用哪个特定类。 接口添加了一个抽象层,因此您的代码客户端将不依赖于您实现解决方案的方式。 他们只知道你会提供他们,界面中有什么。

接口在更复杂的场景中是有用的,例如

(1)你需要多重inheritance(在c#中你不能从2个类inheritance),例如你有接口IProduct,IDisposable。 并非所有产品都需要处理,因此在所有产品上实施它等都没有意义。

(2)当您使用dependency injection(控制反转)和模拟框架(例如RhinoMocks)进行unit testing时 – 那么您必须使用接口,否则您的模拟框架将无法工作。

你知道,有趣的是,我今天正在和我们的一位开发人员谈论这个话题。

以下示例是解释界面及其可用性的最简单方法。

 interface IGraphicsRenderer { Render(List triangles); } 

那么你可能有两种类型的渲染引擎,Direct3D或OpenGL

 class Direct3DRenderer : IGraphicsRenderer { public void Render(List triangles); } class OpenGLRenderer: IGraphicsRenderer { public void Render(List triangles); } 

为了表明它的用处,你可能会有一些东西

 IGraphicsRenderer renderer = new Direct3DRenderer(); renderer.Render(foo); 

要更改渲染器,您需要做的就是更改初始化。

 IGraphicsRenderer renderer = new OpenGLRenderer(); 

Matthew Cochran提供了一个非常好的接口类比

  • 为什么使用接口?

“这使得导航变得更容易”代码世界“。想象一下,如果不是学习驾驶汽车然后能驾驶任何汽车,我们必须学习如何驾驶我们进入的每辆汽车的每个实例如果在学习了如何驾驶福特平托之后我们必须重新开始才能找到野马,那将是非常低效的。一种更有效的方法是处理汽车界面:方向盘,转向灯,这样,无论在接口的后端实现什么,我们都不在乎,因为它最终订阅了基本的汽车合同,这就是我们将如何处理它(通过界面) )2。

除了上面的一般解释,大多数现代软件设计模式,非常依赖于Dependendency Injection等接口

  • 控制容器和 Martin Fowler 的dependency injection

考虑这个例子:

你有一个能够播放媒体文件(mp3)的类。 您将该课程提供给尝试播放MPEG类型文件的朋友。 如果不对你的class级做出重大改变,他就不可能这样做。

 public class MusicPlayer { void Play(Mp3 _mp3File){} } 

考虑一下

而不是将mp3文件的类型传递给Play Method,如果传递此方法,则从类型MediaType的接口派生。

  public interface MediaType { } public class Mp3 : MediaType { } public class MPEG : MediaType { } 

和class级:

  public class MusicPlayer { void Play(MediaType _mediaFile){} } 

在这种情况下,您可以派生另一种MediaFile类型,并从MediaType中获取,如MPEG,并将其传递给Play方法,它将很乐意接受它并为您播放(提供的逻辑)。

  public class TestPlayers { public void PlayMedia() { MusicPlayer musicPlayer = new MusicPlayer(); musicPlayer.Play(new Mp3()); musicPlayer.Play(new MPEG()); } } 

希望这可以帮助

如果有太多类来自Interface类,那么确保所有类都实现了一个Method。

然后如果您的界面发生变化(例如:

  public Interface IAnimal { public void Talk(); public void Eat(); } 

然后你添加另一个方法

  public Interface IAnimal { public void Talk(); public void Sleep(); public void Eat(); } 

然后你可以确保所有这些都将实现Sleep()方法。 如果你有太多来自IAnimal Inteface的类,那么你必须为所有这些类实现Sleep()。 这有助于您尽可能简单地扩展派生类

当然,您可以实现接口中声明的方法而无需实现接口。 简单的put,接口只是确保你不要忘记它(如果没有实现任何接口成员,它们将给你编译错误)。

我想你想要一个非常简单的答案。

有两种类型的inheritance:

  • TYPE 1:接口inheritance(简单来说:当inheritance类的外部时)
  • TYPE 2:实现inheritance(当inheritance类的内部时)

如果你写

 class MyClass : Base {} 

你正在使用BOTH类型1和2.但是如果你实现了一个清除类型1的接口。

类型1用于多态用途,类型2用于代码重用。

所以最重要的是,如果你想使用多态,但你

  • 不想提供任何实现
  • 或者根本做不到。 主要是在多重inheritance的情况下 – 注意:c ++允许它,它遵循另一种哲学

接口适合你:)

还有另一种用途(例如强制执行方法),但在我看来,这就是重点。

接口用于设计。 实际实现遵循设计中定义的内容(读取接口)。 接口的概念使人们可以灵活地设计系统,而无需深入了解实现的细节,或通过在将来实现接口来保持设计的可扩展性。 这也称为抽象。

虽然界面在设计时提供了灵活性,但它在实现时设置了约束。 接口的任何实现都需要完成,这意味着需要在实现时实现接口中定义的所有规范。 此时的另一个灵活性是可以在一个类中实现多个接口。

这是一个非常强大的概念,在设计时提供了极高的灵活性,并确保实施不会破坏设计。