我应该何时使用接口,何时使用基类?
如果我不想实际定义方法的基本实现,它应该始终是一个接口吗?
如果我有狗和猫的课。为什么我要实现IPet而不是PetBase?我可以理解为ISheds或IBarks(IMakesNoise?)提供接口,因为它们可以逐个宠物放置,但我不知道该为普通宠物使用哪个接口。
我应该何时使用接口,何时使用基类?
如果我不想实际定义方法的基本实现,它应该始终是一个接口吗?
如果我有狗和猫的课。为什么我要实现IPet而不是PetBase?我可以理解为ISheds或IBarks(IMakesNoise?)提供接口,因为它们可以逐个宠物放置,但我不知道该为普通宠物使用哪个接口。
当前回答
我建议尽可能使用组合而不是继承。使用接口,但对基本实现使用成员对象。这样,您可以定义一个工厂,该工厂构造对象以某种方式运行。如果要更改行为,则创建一个新的工厂方法(或抽象工厂),以创建不同类型的子对象。
在某些情况下,如果所有可变行为都在帮助对象中定义,那么您可能会发现主对象根本不需要接口。
因此,您可能会得到一个带有IFurBehavior参数的宠物,而不是IPet或PetBase。IFurBehavior参数由PetFactory的CreateDog()方法设置。shed()方法调用的就是这个参数。
如果你这样做,你会发现你的代码更加灵活,你的大多数简单对象都处理非常基本的系统范围行为。
即使在多种继承语言中,我也推荐这种模式。
其他回答
这取决于您的要求。如果IPet足够简单,我更愿意实现它。否则,如果PetBase实现了大量您不想复制的功能,那么就试试看。
实现基类的缺点是需要重写(或新的)现有方法。这使它们成为虚拟方法,这意味着您必须小心如何使用对象实例。
最后,.NET的单一继承让我很头疼。一个天真的例子:假设你正在创建一个用户控件,那么你就继承了UserControl。但是,现在你被禁止继承PetBase。这迫使您重新组织,例如创建PetBase类成员。
接口
大多数语言允许您实现多个接口修改接口是一项突破性的更改。所有实现都需要重新编译/修改。所有成员都是公共的。实现必须实现所有成员。接口有助于解耦。您可以使用模拟框架模拟接口后面的任何内容接口通常表示一种行为接口实现彼此分离/隔离
基类
允许您添加一些通过派生免费获得的默认实现(从C#8.0通过接口可以获得默认实现)除了C++,您只能从一个类派生。即使可以从多个类中选择,这通常也是一个坏主意。更改基类相对容易。派生不需要做任何特殊的事情基类可以声明可由派生访问的受保护函数和公共函数抽象基类不能像接口那样容易被模仿基类通常表示类型层次结构(IS A)类派生可能会依赖于一些基本行为(具有复杂的父实现知识)。如果你对一个人的基本实现进行更改并打破其他人,事情可能会很混乱。
列出你的对象必须要做的事情,你的对象可以做的事情。必须指明你的基类型,可以指明你的接口。
例如,您的PetBase必须呼吸,而您的IPet可能会DoTricks。
对问题域的分析将帮助您定义精确的层次结构。
我通常在需要之前都不会实现。与抽象类相比,我更喜欢接口,因为这提供了更多的灵活性。如果在某些继承类中有共同的行为,我会将其上移并创建一个抽象基类。我不认为两者都有必要,因为它们本质上服务于相同的目的,而且两者都有一种糟糕的代码气味(imho),解决方案被过度设计了。
继承还有其他优点,例如变量能够保存父类或继承类的对象(无需将其声明为泛型,如“object”)。
例如,在.NET WinForms中,大多数UI组件都是从System.Windows.Forms.Control派生的,因此声明为的变量可以“容纳”几乎所有UI元素,无论是按钮、ListView还是其他元素。当然,现在你不能访问项目的所有财产或方法,但你可以拥有所有基本的东西——这可能很有用。