我应该何时使用接口,何时使用基类?
如果我不想实际定义方法的基本实现,它应该始终是一个接口吗?
如果我有狗和猫的课。为什么我要实现IPet而不是PetBase?我可以理解为ISheds或IBarks(IMakesNoise?)提供接口,因为它们可以逐个宠物放置,但我不知道该为普通宠物使用哪个接口。
我应该何时使用接口,何时使用基类?
如果我不想实际定义方法的基本实现,它应该始终是一个接口吗?
如果我有狗和猫的课。为什么我要实现IPet而不是PetBase?我可以理解为ISheds或IBarks(IMakesNoise?)提供接口,因为它们可以逐个宠物放置,但我不知道该为普通宠物使用哪个接口。
当前回答
这是非常特定于.NET的,但《框架设计指南》一书认为,一般来说,类在不断发展的框架中提供了更多的灵活性。一旦一个接口交付,您就没有机会在不破坏使用该接口的代码的情况下更改它。然而,对于类,你可以修改它,而不是破坏链接到它的代码。只要你做了正确的修改,包括添加新的功能,你就可以扩展和发展你的代码。
Krzysztof Cwalina在第81页上说:
在.NETFramework的三个版本中,我已经与我们团队中的许多开发人员讨论了这一指南。他们中的许多人,包括那些最初不同意该指南的人,都表示他们后悔将一些API作为接口提供。我甚至没有听说过一个案例,其中有人后悔他们运送了一节课。
也就是说,当然有接口的地方。作为一般准则,始终提供接口的抽象基类实现,作为实现接口的方法的示例。在最佳情况下,基类将节省大量工作。
其他回答
基类的继承者应该具有“is a”关系。接口表示“实现”关系。因此,只有在继承者将维护关系时才使用基类。
关于C#,在某些意义上,接口和抽象类可以互换。然而,区别在于:i)接口不能实现代码;ii)由于这一点,接口不能进一步调用堆栈上的子类;以及iii)抽象类只能在类上继承,而多个接口可以在类上实现。
接口
大多数语言允许您实现多个接口修改接口是一项突破性的更改。所有实现都需要重新编译/修改。所有成员都是公共的。实现必须实现所有成员。接口有助于解耦。您可以使用模拟框架模拟接口后面的任何内容接口通常表示一种行为接口实现彼此分离/隔离
基类
允许您添加一些通过派生免费获得的默认实现(从C#8.0通过接口可以获得默认实现)除了C++,您只能从一个类派生。即使可以从多个类中选择,这通常也是一个坏主意。更改基类相对容易。派生不需要做任何特殊的事情基类可以声明可由派生访问的受保护函数和公共函数抽象基类不能像接口那样容易被模仿基类通常表示类型层次结构(IS A)类派生可能会依赖于一些基本行为(具有复杂的父实现知识)。如果你对一个人的基本实现进行更改并打破其他人,事情可能会很混乱。
我有一个粗略的经验法则
功能:可能在所有部分都不同:界面。
数据和功能,部分基本相同,部分不同:抽象类。
数据和功能,实际工作,如果只进行了轻微的修改:普通(具体)类
数据和功能,没有计划的更改:带有最终修饰符的普通(具体)类。
数据,可能还有功能:只读:枚举成员。
这是非常粗略和准备好的,并且根本没有严格定义,但是有一个范围是从所有内容都要更改的接口到所有内容都像只读文件一样固定的enums。
如果除了您的类型成员之外,其他开发人员确实没有任何理由希望使用自己的基类,并且您预见到版本控制问题,那么您应该使用基类(请参见http://haacked.com/archive/2008/02/21/versioning-issues-with-abstract-base-classes-and-interfaces.aspx).
如果继承开发人员有任何理由使用自己的基类来实现类型的接口,并且您没有看到接口发生变化,那么就使用接口。在这种情况下,为了方便起见,您仍然可以加入实现接口的默认基类。