接口:为什么我似乎无法把握他们?

有人能为我揭开界面的神秘面纱,或者指出一些很好的例子。 我不断看到接口在这里和那里popup,但我从来没有真正接触到接口的良好解释或何时使用它们?

我正在谈论界面与抽象类的接口

接口允许您针对“描述”而不是types进行编程,从而使您可以更松散地关联软件的各个元素。

您可以这样想:您想与您旁边的多维数据集中的某个人共享数据,因此您需要拔出闪存盘并进行复制/粘贴。 你走到隔壁,那家伙说“是USB吗?” 你说是的 – 所有的设置。 闪光棒的大小和制造商无关紧要 – 重要的是它是USB。

以同样的方式,接口可以使您的开发生成。 用另一个比喻 – 想象一下你想创build一个虚拟绘制汽车的应用程序。 你可能有这样的签名:

public void Paint(Car car, System.Drawing.Color color)... 

这将工作,直到你的客户说“现在我想画卡车”,所以你可以这样做:

 public void Paint (Vehicle vehicle, System.Drawing.Color color)... 

这将扩大你的应用程序…直到你的客户说:“现在我想画房子!” 你从一开始就可以做的是创build一个接口:

 public interface IPaintable{ void Paint(System.Drawing.Color color); } 

…并将其传递给你的例程:

 public void Paint(IPaintable item, System.Drawing.Color color){ item.Paint(color); } 

希望这是有道理的 – 这是一个非常简单的解释,但希望能得到它的核心。

接口在类和调用它的代码之间build立一个契约。 他们还允许你有类似的类,实现相同的接口,但做不同的行动或事件,而不必知道你实际工作。 这可能更有意义,所以让我在这里尝试一下。

假设你有一个叫Dog,Cat和Mouse的课程。 这些类中的每一个都是一个Pet,理论上你可以从另一个类Petinheritance它们,但是这里是问题。 宠物和自己都不会做任何事情。 你不能去商店买一只宠物。 你可以去买一只狗或一只猫,但一只宠物是一个抽象的概念,而不是具体的。

所以你知道宠物可以做某些事情。 他们可以睡觉,或者吃东西等。所以你定义了一个名为IPet的接口,它看起来像这样(C#语法)

 public interface IPet { void Eat(object food); void Sleep(int duration); } 

每个Dog,Cat和Mouse类都实现IPet。

 public class Dog : IPet 

所以现在每个类都必须自己实现“吃饭睡觉”。 是的,你有合同…现在有什么意义。

接下来让我们假设你想创build一个名为PetStore的新对象。 这不是一个很好的PetStore,所以他们基本上只是卖给你一个随机的宠物(是的,我知道这是一个人为的例子)。

 public class PetStore { public static IPet GetRandomPet() { //Code to return a random Dog, Cat, or Mouse } } IPet myNewRandomPet = PetStore.GetRandomPet(); myNewRandomPet.Sleep(10); 

问题是你不知道什么types的宠物会。 感谢界面,尽pipe你知道它会吃,睡觉。

所以这个答案可能没有什么帮助,但一般的想法是,接口让你做像dependency injection和控制反转那样的整齐的东西,你可以得到一个对象,有一个明确的对象可以做的东西,而不是真正的东西知道该对象的具体types是什么。

最简单的答案是接口定义了你的类可以做什么。 这是一个“契约”,说你的class级将能够做到这一点。

 Public Interface IRollOver Sub RollOver() End Interface Public Class Dog Implements IRollOver Public Sub RollOver() Implements IRollOver.RollOver Console.WriteLine("Rolling Over!") End Sub End Class Public Sub Main() Dim d as New Dog() Dim ro as IRollOver = TryCast(d, IRollOver) If ro isNot Nothing Then ro.RollOver() End If End Sub 

基本上,你保证Dog类只要继续实现那个接口,就总是有翻转的能力。 如果猫能获得RollOver()的能力,他们也可以实现这个接口,并且当他们要求RollOver()时,你可以同时对待Dogs和Cats。

当你开车的朋友,你或多或less知道如何做到这一点。 这是因为传统的汽车都有一个非常相似的界面:方向盘,踏板等等。 把这个界面想象成汽车制造商和司机之间的合同。 作为一个驱动程序(软件界面的用户/客户端),您不需要了解不同汽车的详细信息就可以驱动它们:例如,您只需要知道转动方向盘就可以车转。 作为一个汽车制造商(软件界面实现的提供者),您清楚地了解您的新车应该具备哪些行为,以便司机可以在不需要额外培训的情况下使用它们。 这个合同是软件devise中的人们称之为解耦(用户与提供者) – 客户端代码是使用接口而不是特定的实现,因此不需要知道对象的细节实现界面。

接口是一种机制,可以减less系统中不同的,可能不同的部分之间的耦合。

从.net的angular度来看

  • 接口定义是操作和/或属性的列表
  • 接口方法总是公开的
  • 界面本身不必公开

在创build实现接口的类时,必须提供由接口定义的所有方法和属性的显式或隐式实现。

进一步.net只有单一的inheritance,接口是一个对象暴露方法的其他对象是不知道的,或不在它的类层次结构的必要性。 有时我们称之为暴露行为。

一个更具体的例子是:

考虑一下,我们有许多DTO(数据传输对象),它们具有最后一次更新的属性,以及最后一次更新的属性。 问题是并不是所有的DTO都有这个属性,因为它并不总是相关的。 同时,我们希望有一个通用机制来保证这些属性在提交给工作stream时可用,但工作stream对象应该与提交的对象松散耦合。 即提交工作stream方法不应该真正了解每个对象的所有细节,工作stream中的所有对象都不一定是DTO对象。

 // first pass - not maintainable void SubmitToWorkflow(object o, User u) { if( o is StreetMap ) { var map = (StreetMap)o; map.LastUpdated = DateTime.UtcNow; map.UpdatedByUser = u.UserID; } else if( o is Person ) { var person = (Person)o; person.LastUpdated = DateTime.Now; // whoops .. should be UtcNow person.UpdatedByUser = u.UserID; } // whoa - very unmaintainable. 

在上面的代码中, SubmitToWorkflow()必须知道每个对象。 另外,代码与一个大量的if / else /开关混为一谈,违反了不要自行重复(DRY)的原则,并且要求开发人员在每次将新对象添加到系统时记住复制/粘贴更改。

 // second pass - brittle void SubmitToWorkflow(object o, User u) { if( o is DTOBase ) { DTOBase dto = (DTOBase)o; dto.LastUpdated = DateTime.UtcNow; dto.UpdatedByUser = u.UserID; } 

略好,但仍脆。 如果我们想提交其他types的对象,我们仍然需要更多的case语句。 等等

 // third pass pass - also brittle void SubmitToWorkflow(DTOBase dto, User u) { dto.LastUpdated = DateTime.UtcNow; dto.UpdatedByUser = u.UserID; 

仍然脆弱,这两种方法强加的限制,所有的DTO的必须实现这个属性,我们表示并不普遍适用。 有些开发人员可能会试图写无所作为的方法,但是这种方法味道不好。 我们不希望class级假装他们支持更新跟踪,但不要。

接口,他们如何帮助?

如果我们定义一个非常简单的界面:

 public interface IUpdateTracked { DateTime LastUpdated { get; set; } int UpdatedByUser { get; set; } } 

任何需要这个自动更新跟踪的类都可以实现这个接口。

 public class SomeDTO : IUpdateTracked { // IUpdateTracked implementation as well as other methods for SomeDTO } 

工作stream方法可以做得更通用,更小,更易于维护,并且无论有多less类实现接口(DTO或其他),因为它只处理接口,它将继续工作。

 void SubmitToWorkflow(object o, User u) { IUpdateTracked updateTracked = o as IUpdateTracked; if( updateTracked != null ) { updateTracked.LastUpdated = DateTime.UtcNow; updateTracked.UpdatedByUser = u.UserID; } // ... 
  • 我们可以注意到variablesvoid SubmitToWorkflow(IUpdateTracked updateTracked, User u)可以保证types的安全性,但是在这种情况下它看起来并不相关。

在我们使用的一些生产代码中,我们有代码生成来从数据库定义中创build这些DTO类。 开发人员所做的唯一事情就是正确地创build字段名称,并用接口装饰类。 只要属性被称为LastUpdated和UpdatedByUser,它就可以工作。

也许你在问什么如果我的数据库是遗留的,这是不可能的? 你只需要多打一点儿; 接口的另一大特点是它们可以让你在类之间build立一个桥梁。

在下面的代码中,我们有一个虚构的LegacyDTO ,一个预先存在的具有相似命名字段的对象。 它正在实现IUpdateTracked接口,以桥接现有但不同名称的属性。

 // using an interface to bridge properties public class LegacyDTO : IUpdateTracked { public int LegacyUserID { get; set; } public DateTime LastSaved { get; set; } public int UpdatedByUser { get { return LegacyUserID; } set { LegacyUserID = value; } } public DateTime LastUpdated { get { return LastSaved; } set { LastSaved = value; } } } 

你可能会很酷,但不是有多个属性混淆? 或者如果已经有这些属性会发生什么,但是他们的意思是别的吗? .net给你明确实现接口的能力。 这意味着IUpdateTracked属性只有在我们使用对IUpdateTracked的引用时才可见。 请注意声明中没有public修饰符,声明中包含接口名称。

 // explicit implementation of an interface public class YetAnotherObject : IUpdatable { int IUpdatable.UpdatedByUser { ... } DateTime IUpdatable.LastUpdated { ... } 

有了这么多的灵活性来定义类如何实现接口,开发人员可以自由地将对象从使用它的方法中分离出来。 接口是一个打破耦合的好方法。

接口比这更多。 这只是一个简化的现实生活中的例子,它利用了基于接口的编程的一个方面。

正如我前面提到的和其他响应者一样,您可以创build接受和/或返回接口引用的方法,而不是特定的类引用。 如果我需要在列表中find重复项,我可以编写一个方法来获取并返回一个IList (一个定义在列表上的操作的接口),我不受限于具体的集合类。

 // decouples the caller and the code as both // operate only on IList, and are free to swap // out the concrete collection. public IList<T> FindDuplicates( IList<T> list ) { var duplicates = new List<T>() // TODO - write some code to detect duplicate items return duplicates; } 

版本警告

如果它是一个公共接口,你声明我保证接口x看起来像这样! 一旦你发布了代码并发布了界面,你不应该改变它。 只要消费者代码开始依赖于该接口,就不希望在现场破坏他们的代码。

看到这个Haacked的post进行了一个很好的讨论。

接口与抽象(基础)类

抽象类可以提供实现,而接口不能。 如果您遵循NVPI(非虚拟公共接口)模式等指导原则,抽象类在版本控制方面的某些方面更加灵活。

值得重申的是,在.net中,一个类只能从一个类inheritance,而一个类可以实现尽可能多的接口。

dependency injection

接口和DI的快速总结是使用接口使开发人员能够编写针对接口编程的代码来提供服务。 在实践中,最终可能会有很多小的接口和小类,一个想法是小的类只做一件事,而只有一件事更容易编码和维护。

 class AnnualRaiseAdjuster : ISalaryAdjuster { AnnualRaiseAdjuster(IPayGradeDetermination payGradeDetermination) { ... } void AdjustSalary(Staff s) { var payGrade = payGradeDetermination.Determine(s); s.Salary = s.Salary * 1.01 + payGrade.Bonus; } } 

简而言之,上面的片段显示的好处是,薪酬等级的确定只是注入年度的调整人员。 如何确定薪酬等级对这个class级实际上并不重要。 在testing时,开发人员可以模拟薪酬等级确定结果,以确保薪资调整者的function。 testing也是快速的,因为testing只是testing类,而不是其他所有testing。

这不是一个DI引物,虽然有整本书专门讨论这个问题; 上面的例子非常简单。

这是一个相当“长”的主题,但让我试着简单点。

一个接口是“他们命名它” – 一个合同。 但忘了那个字。

了解它们的最好方法是通过某种伪代码的例子。 这就是我很久以前对他们的了解。

假设你有一个处理消息的应用程序。 消息包含一些东西,如主题,文本等

所以你写你的MessageController来读取数据库,并提取消息。 这很好,直到你突然听到传真也即将实施。 因此,您现在必须阅读“传真”并将其作为消息进行处理!

这很容易变成Spagetti代码。 所以你做什么而不是拥有一个MessageController而不是仅仅控制“Messages”,你可以使用一个名为IMessage的接口 (我只是常见的用法,但不是必需的)。

您的IMessage界面包含您需要确保您能够处理消息的一些基本数据。

所以当你创build你的电子邮件,传真,PhoneCall类,你让他们实现 接口称为IMessage

所以在你的MessageController中,你可以有一个像这样的方法:

 private void ProcessMessage(IMessage oneMessage) { DoSomething(); } 

如果你没有使用接口,你必须有:

 private void ProcessEmail(Email someEmail); private void ProcessFax(Fax someFax); etc. 

因此,通过使用通用接口,您只需确保ProcessMessage方法能够使用它,无论它是传真,电子邮件,电话等等。

为什么或如何

因为接口是一个指定了一些你必须遵守(或实现)以便能够使用它的事物的契约 。 把它想成一个徽章 。 如果您的对象“传真”没有IMessage接口,那么您的ProcessMessage方法将无法工作,它会给你一个无效的types,因为你传递一个传真给一个方法,期望一个IMessage目的。

你明白了吗?

尽pipe是真实的对象types, 将接口看作是可用的方法和属性的“子集”。 如果原始对象(传真,电子邮件,PhoneCall等)实现了该接口,则可以通过需要该接口的方法安全地传递它。

这里隐藏着更多的魔法,你可以将界面转换回原来的对象:

传真myFax =(传真)SomeIMessageThatIReceive;

.NET 1.1中的ArrayList()有一个很好的界面叫做IList。 如果你有一个IList(非常“通用”),你可以把它转换成一个ArrayList:

 ArrayList ar = (ArrayList)SomeIList; 

野外有数千个样本。

像ISortable,IComparable等接口定义了你必须在你的类中实现的方法和属性,以实现这个function。

为了扩展我们的示例,如果types是IMessage,则可以将电子邮件,传真,电话呼叫列表全部放在同一列表中,但是如果对象只是电子邮件,传真等,则不能将它们全部放在一起。

如果你想sorting(或枚举)你的对象,你需要他们来实现相应的接口。 在.NET示例中,如果您有一个“传真”对象列表,并希望能够使用MyList.Sort()对其进行sorting ,则需要将传真类设置为这样:

 public class Fax : ISorteable { //implement the ISorteable stuff here. } 

我希望这给你一个提示。 其他用户可能会发布其他很好的例子。 祝你好运! 并拥抱界面的力量。

警告 :并不是所有的接口都是好的,他们有一些问题,OOP纯粹主义者会对此发动一场战争。 我将留在一边。 Interfce(至less在.NET 2.0中)的一个缺点是你不能拥有PRIVATE成员或者保护,它必须是公共的。 这是有道理的,但有时你希望你可以简单地声明为私人或保护的东西。

除了程序devise语言中的函数接口外,在向其他expressiondevise思想时,它们也是一个强大的语义工具。

一个devise良好的界面的代码基础突然变得更容易讨论。 “是的,你需要一个CredentialsManager来注册新的远程服务器。” “将一个PropertyMap传递给ThingFactory以获得一个工作实例。”

能够用一个单词来处理复杂的事情是非常有用的。

接口让你以通用的方式对对象进行编码。 例如,假设你有一个发送报告的方法。 现在说你有一个新的需求,在你需要写一个新的报告。 如果你能重复使用你已经写好的方法,这将是很好的吗? 接口使这一点变得简单:

 interface IReport { string RenderReport(); } class MyNewReport : IReport { public string RenderReport() { return "Hello World Report!"; } } class AnotherReport : IReport { public string RenderReport() { return "Another Report!"; } } //This class can process any report that implements IReport! class ReportEmailer() { public void EmailReport(IReport report) { Email(report.RenderReport()); } } class MyApp() { void Main() { //create specific "MyNewReport" report using interface IReport newReport = new MyNewReport(); //create specific "AnotherReport" report using interface IReport anotherReport = new AnotherReport(); ReportEmailer reportEmailer = new ReportEmailer(); //emailer expects interface reportEmailer.EmailReport(newReport); reportEmailer.EmailReport(anotherReport); } } 

接口也是多态的关键,是“三大支柱”之一。

上面有人提到,多态只是一个给定的类可以采取不同的“forms”。 意思是说,如果我们有两个类,“狗”和“猫”,都实现了接口“INeedFreshFoodAndWater”(hehe) – 你的代码可以做这样的事情(伪代码):

 INeedFreshFoodAndWater[] array = new INeedFreshFoodAndWater[]; array.Add(new Dog()); array.Add(new Cat()); foreach(INeedFreshFoodAndWater item in array) { item.Feed(); item.Water(); } 

这是很强大的,因为它允许你抽象地处理不同类别的对象,并允许你做一些事情,比如让对象更加松散地耦合等等。

好吧,这是关于抽象类与接口…

从概念上讲,抽象类是作为基类使用的。 通常他们自己已经提供了一些基本的function,并且子类必须提供他们自己的抽象方法的实现(那些抽象基类中没有实现的方法)。

接口主要用于将客户端代码与特定实现的细节分离。 另外,有时在不改变客户端代码的情况下切换实现的能力使客户端代码更通用。

在技​​术层面上,在抽象类和接口之间划分界限比较困难,因为在某些语言(如C ++)中没有语法差异,或者因为抽象类也可以用于解耦或泛化。 使用抽象类作为接口是可能的,因为每个基类定义了一个它的所有子类都应该遵守的接口(即应该可以使用子类而不是基类)。

简单地说:一个接口是一个定义了方法的类,但是没有实现它们。 相比之下,抽象类有一些实现的方法,但不是全部。

将界面视为合同。 当一个类实现一个接口时,它基本上同意遵守该合同的条款。 作为消费者,您只关心您拥有的物品可以履行合同义务。 他们的内部工作和细节并不重要。

接口是强制对象实现一定数量的function的一种方式,而不必使用inheritance(这导致强耦合的代码,而不是通过使用接口可以实现的松散耦合)。

接口描述function,而不是实现。

在Java中使用接口与抽象类的一个很好的理由是子类不能扩展多个基类,但它可以实现多个接口。

Java不允许多重inheritance(出于很好的理由,查找可怕的钻石),但是如果你想让你的类提供多组行为呢? 假设你想让任何使用它的人知道它可以被序列化,也可以在屏幕上画自己。 答案是实现两个不同的接口。

由于接口不包含自己的实现,也没有实例成员,因此可以安全地在同一个类中实现其中的几个,而且没有歧义。

不利的一面是你将不得不分别在每个类中实现。 所以如果你的层次结构很简单,并且实现的一部分对于所有的inheritance类都应该是相同的,那么就使用一个抽象类。

像其他人在这里所说的那样,接口定义了一个契约(使用接口的类将如何“看”)和抽象类定义共享的function。

让我们看看代码是否有帮助:

 public interface IReport { void RenderReport(); // this just defines the method prototype } public abstract class Reporter { protected void DoSomething() { // this method is the same for every class that inherits from this class } } public class ReportViolators : Reporter, IReport { public void RenderReport() { // some kind of implementation specific to this class } } public class ClientApp { var violatorsReport = new ReportViolators(); // the interface method violatorsReport.RenderReport(); // the abstract class method violatorsReport.DoSomething(); } 

假设你指的是静态types的面向对象语言中的接口,主要用于声明你的类遵循特定的合约或协议。

假设你有:

 public interface ICommand { void Execute(); } public class PrintSomething : ICommand { OutputStream Stream { get; set; } String Content {get; set;} void Execute() { Stream.Write(content); } } 

现在你有一个可replace的命令结构。 实现IExecute的任何类的实例都可以存储在某种列表中,例如实现IEnumerable的东西,并且可以遍历它并执行每一个,知道每个对象都会做正确的事情。 你可以通过实现CompositeCommand来创build一个复合命令,它将有自己的命令列表来运行,或者一个LoopingCommand来反复运行一组命令,那么你将拥有一个简单的解释器。

当你可以将一组对象减less到它们都有的共同行为时,你可能有理由提取一个接口。 另外,有时你可以使用接口来防止对象意外地侵入该类的关注点; 例如,您可以实现一个只允许客户端检索的接口,而不是更改对象中的数据,并使大多数对象只接收对检索接口的引用。

当你的界面相对简单并且做一些假设时,界面工作得最好。

查阅Liskov替代原则来更好地理解这一点。

一些像C ++这样的静态types语言不支持将接口作为第一类的概念,所以你使用纯粹的抽象类来创build接口。

更新由于你似乎在问抽象类与接口,这里是我最喜欢的简单化:

  • 接口定义了function和特性。
  • 抽象类定义核心function。

通常,在构build抽象类之前,我会进行抽取接口重构。 如果我认为应该有一个创build合同(具体来说,应该总是由子类支持特定types的构造函数),那么我更可能构build一个抽象类。 但是,我很less在C#/ java中使用“纯粹”的抽象类。 我更有可能通过至less一个包含有意义行为的方法实现一个类,并使用抽象方法来支持由该方法调用的模板方法。 然后抽象类是一个行为的基本实现,所有具体的子类可以利用而不必重新实现。

简单的答案:一个接口是一堆方法签名(+返回types)。 当一个对象说它实现了一个接口,你知道它暴露了这个方法集合。

接口是以强types和多态的方式实现约定的一种方式。

.NET中的一个好的现实世界的例子是IDisposable。 实现IDisposable接口的类强制该类实现Dispose()方法。 如果这个类没有实现Dispose(),那么当你尝试构build的时候你会得到一个编译器错误。 另外,这个代码模式:

 using (DisposableClass myClass = new DisposableClass()) { // code goes here } 

当执行退出内部块时将导致myClass.Dispose()自动执行。

然而,这很重要,对于你的Dispose()方法应该做什么没有执行。 你可以让你的Dispose()方法从文件中select随机配方,并通过电子邮件发送到分发列表,编译器不关心。 IDisposable模式的目的是为了更容易地清理资源。 如果一个类的实例保存在文件句柄中,则IDisposable使得将释放和清理代码集中在一个地方变得非常容易,并促进一种确保始终发生释放的使用风格。

这是接口的关键。 它们是简化编程约定和devise模式的一种方法。 其中,正确使用时,促进更简单,自我logging代码更容易使用,更容易维护,更正确。

这里是我经常使用的一个db相关的例子。 让我们说你有一个对象和一个容器对象像一个列表。 让我们假设有时您可能想要以特定顺序存储对象。 假设序列与数组中的位置无关,而是对象是更大对象集合的子集,序列位置与数据库SQL过滤相关。

要跟踪您的自定义序列位置,您可以使您的对象实现一个自定义的界面。 自定义界面可以调解维护这种序列所需的组织努力。

例如,您感兴趣的序列与logging中的主键无关。 有了实现接口的对象,你可以说myObject.next()或myObject.prev()。

我和你有同样的问题,我发现“合同”的解释有点混乱。

如果指定某个方法将IEnumerable接口作为in-parameter接口,则可以说这是一个约定,指定参数必须是从IEnumerable接口inheritance的types,因此支持在IEnumerable接口中指定的所有方法。 如果我们使用抽象类或普通类,情况也是如此。 任何从这些类inheritance的对象都可以作为参数传入。 无论如何,无论基类是普通类,抽象类还是接口,都可以说inheritance对象支持基类中的所有公共方法。

所有抽象方法的抽象类与接口基本相同,所以可以说接口只是一个没有实现方法的类。 您实际上可以从语言中删除接口,而只是使用抽象类而只使用抽象方法。 我认为我们把它们分开的原因是出于语义的原因,但是出于编码的原因,我没有看到原因,只是觉得混乱。

另一个build议可能是将接口重命名为接口类,因为接口只是类的另一个变体。

在某些语言中有微妙的差异,允许一个类只能inheritance一个类,但多个接口,而在其他语言中可以有很多这两个接口,但这是另一个问题,而不是直接相关

理解接口最简单的方法是从考虑什么类inheritance意味着开始。 它包括两个方面:

  1. 派生类的成员可以使用基类的公有成员或受保护成员作为自己的成员。
  2. 派生类的成员可以被代码使用,这些代码需要基类的成员(意味着它们是可替代的)。

Both of these features are useful, but because it is difficult to allow a class to use members of more than one class as its own, many languages and frameworks only allow classes to inherit from a single base class. On the other hand, there is no particular difficulty with having a class be substitutable for multiple other unrelated things.

Further, because the first benefit of inheritance can be largely achieved via encapsulation, the relative benefit from allowing multiple-inheritance of the first type is somewhat limited. On the other hand, being able to substitute an object for multiple unrelated types of things is a useful ability which cannot be readily achieved without language support.

Interfaces provide a means by which a language/framework can allow programs to benefit from the second aspect of inheritance for multiple base types, without requiring it to also provide the first.

Most of the interfaces you come across are a collection of method and property signatures. Any one who implements an interface must provide definitions to what ever is in the interface.

Interface is like a fully abstract class. That is, an abstract class with only abstract members. You can also implement multiple interfaces, it's like inheriting from multiple fully abstract classes. Anyway.. this explanation only helps if you understand what an abstract class is.

Interfaces require any class that implements them to contain the methods defined in the interface.

The purpose is so that, without having to see the code in a class, you can know if it can be used for a certain task. For example, the Integer class in java implements the comparable interface, so, if you only saw the method header (public class String implements Comparable), you would know that it contains a compareTo() method.

Moved to this question after this question was closed as a duplicate, in hope that it will help someone:

In your simple case, you could achieve something similar to what you get with interfaces by using a common base class that implements show() (or perhaps defines it as abstract). Let me change your generic names to something more concrete, Eagle and Hawk instead of MyClass1 and MyClass2 . In that case you could write code like

 Bird bird = GetMeAnInstanceOfABird(someCriteriaForSelectingASpecificKindOfBird); bird.Fly(Direction.South, Speed.CruisingSpeed); 

That lets you write code that can handle anything that is a Bird . You could then write code that causes the Bird to do it's thing (fly, eat, lay eggs, and so forth) that acts on an instance it treats as a Bird . That code would work whether Bird is really an Eagle , Hawk , or anything else that derives from Bird .

That paradigm starts to get messy, though, when you don't have a true is a relationship. Say you want to write code that flies things around in the sky. If you write that code to accept a Bird base class, it suddenly becomes hard to evolve that code to work on a JumboJet instance, because while a Bird and a JumboJet can certainly both fly, a JumboJet is most certainly not a Bird .

Enter the interface.

What Bird (and Eagle , and Hawk ) do have in common is that they can all fly. If you write the above code instead to act on an interface, IFly , that code can be applied to anything that provides an implementation to that interface.