类应该何时实现接口,何时不应该?

时间:2010-09-07 20:05:20

标签: c# .net interface

一个类是否应该始终实现一个接口,以便在类上强制执行某种“契约”?

什么时候不应该实现一个接口?

编辑:意思,什么时候让一个类实现一个接口是值得的?为什么没有一个类只有公共成员和私有成员具有各种访问者/设置者功能?

(注:不谈COM)

7 个答案:

答案 0 :(得分:16)

不,并不总是需要界面 - 该类的公共成员已经形成合同。

当您希望能够在提供类似功能时将一个类交换为另一个类时,接口非常有用。使用接口可以将合同与特定实现分离。然而,这种脱钩并不总是必要或有用的。

.NET框架中的许多类都没有实现任何接口。

答案 1 :(得分:4)

仅在需要时使用界面 那就是:当你想为某个抽象实现不同的实现时。

在将来,似乎为特定类创建一个接口会更好(因为例如,您希望为同一个概念创建另一个实现),那么您始终可以从您的界面创建接口现有的课程。 (ExtractInterface refactoring

答案 2 :(得分:2)

当您进行单元测试时,接口变得更加必要,但这一切都取决于您的开发环境。正如马克所说,界面是合同,实施它会迫使你遵守合同的“规则”。

如果您尝试强制执行某些方法,那么使用接口是完美的。

这里有一些不错的例子:

答案 3 :(得分:2)

接口,这里意味着代码构造而不是设计抽象,支持代码设计的基本原则,称为“松散耦合”。有一些更多的派生原则告诉你代码应该如何松散耦合,但主要的是,松散耦合有助于允许更改代码以尽可能小地影响代码库。

例如,考虑一些任意复杂性的计算。此计算由6个不同的类使用,因此为避免重复代码,计算将封装在其自己的类Calculator中。这6个类都包含对Calculator的引用。现在,假设您的客户来找您,并说在一次使用计算器时,如果满足某些条件,则应使用不同的计算。您可能只想将这两个规则(使用规则和业务规则)和新的计算算法放入Calculator类中,但如果您这样做,那么将会发生两件事;首先,你让计算器知道它的范围之外的一些实现细节(它是如何使用的),它不需要知道,并且可以在以后再次改变。其次,使用计算器的其他5个类,它们按原样正常工作,因为它们引用了更改的类,所以必须重新编译,并且必须进行测试以确保您没有通过更改它来破坏它们的功能。第六节课。

对此的“正确”解决方案是界面。通过定义一个接口ICalculator,它暴露了其他类调用的方法,你打破了6个类对特定类Calculator的具体依赖性。现在,6个类中的每个类都可以引用ICalculator。在其中的5个类中,您提供了他们一直拥有的相同的Calculator类,并且可以正常工作。在6日,您提供了一个了解其他规则的特殊计算器。如果您从一开始就这样做了,那么您就不必触及其他5个类来进行第6次更改。

基本点是,课程不应该知道他们依赖的其他对象的确切性质;他们应该只知道那个对象会为他们做些什么。通过从对象IS中抽象出对象所做的事情,多个对象可以做类似的事情,而需要这些事物的类不必知道差异。

松散耦合以及“高内聚”(对象通常应该是知道如何执行小型,高度相关的任务的专家),是您将看到的大多数软件设计模式的基础你进入了软件开发理论。

与几个答案相反,有一些设计方法(例如SOLID)表明你应该始终将依赖关系设置为抽象,如抽象基类或接口,并且永远不要让一个类依赖于另一个具体类。这里的逻辑是,在商业软件开发中,应用程序的初始需求集非常小,但如果不是保证,那么这组需求将会增长和变化是一个安全的假设。当发生这种情况时,软件必须增长。根据严格的设计原则创建更小的应用程序允许扩展软件,而不会导致设计不良的自然结果的问题(包含大量代码的大型类,以不可预测的方式影响其他类的更改等)。然而,软件开发的艺术,以及它的时间和金钱限制是这样的,你可以(并且必须)聪明并说“从我所知道的这个系统将会增长的方式,这是一个需要的领域设计精良,允许适应,而这另一部分几乎肯定永远不会改变“。如果这些假设发生变化,您可以返回并重构您设计的代码区域,以便在扩展该区域之前更加强大。但是,您必须愿意并且能够在第一次实施后更改代码。

答案 4 :(得分:1)

这又一次归结为“界面”的含义。术语接口和接口之间存在一些歧义。当使用术语Interface时,它表示没有方法声明的对象。当使用术语接口时,它意味着您使用预定义的一组函数(无论它们是否实现),并在必要时使用您的逻辑覆盖它们。一个例子是:

  

抽象类动物
  class Dog extends Animal

在这种情况下,Dog

的Animal ==接口(或合约)
  

界面可衡量的   班级杯实施可衡量的

在这个例子中,可衡量==杯赛界面

答案 5 :(得分:1)

您可能并不总是想要一个界面。考虑您可以使用委托完成类似的任务。在Java中,我将Runnable接口用于多线程应用程序。现在,我在.NET中编程,我非常依赖代表来完成我的多线程应用程序。本文有助于解释代理与接口的需求。

When to Use Delegates Instead of Interfaces (C# Programming Guide)

代理提供了更多的灵活性,就像在Java中一样,我发现我在C中用函数指针完成的任何任务现在需要使用一个接口来创建。

虽然接口有很多种情况。考虑IEnumerable,它旨在允许您迭代各种集合,而无需了解底层代码的工作原理。当您需要将一个类交换为另一个类但需要类似的接口时,接口非常适用。 ICollection和IList提供了一组类似的功能来完成对集合的操作,而不必担心具体细节。

如果您想更好地了解界面,建议您阅读"Head First Design Patterns"

答案 6 :(得分:1)

一个类不应该实现接口/ s,除非你想告诉你程序的其他部分 - “这个类可以做这些事情(但不指定它完成它的功能)”。
你什么时候想那样做? 例如,假设你有一个你有动物的游戏......并且说每当动物看到一个人就会发出声音(无论是树皮,咆哮等)。
如果所有的动物都会实现接口IMakeSound,其中有一个名为MakeSound的方法,那么你就不必关心它应该发出什么样的动物了。所有你需要做的就是使用“IMakeSound”动物的一部分,并称之为方法 我应该补充一点,当一个人在类声明中读取它实现某个接口时,它会告诉他很多关于该类的信息,这是另一个好处。