在实现方面,我应该如何选择基本类型或接口?我尝试了几个例子,但我没有得到完整的想法:(
如何以及为什么会受到高度赞赏的例子..
答案 0 :(得分:41)
基类(抽象与否)可以包含已实现的成员。界面不能。如果所有实现都要执行类似的操作,那么基类可能就是这样,因为所有子类都可以共享基类上成员的相同实现。如果他们不打算共享实现,那么接口可能是最佳选择。
示例:
class Person
{
string Name { get; set; }
}
class Employee : Person
{
string Company { get; set; }
}
Employee继承Person是有道理的,因为Employee类不必定义Name
属性,因为它共享实现。
interface IPolygon
{
double CalculateArea()
}
class Rectangle : IPolygon
{
double Width { get; set; }
double Height { get; set; }
double CalculateArea()
{
return this.Width * this.Height;
}
}
class Triangle : IPolygon
{
double Base { get; set; }
double Height { get; set; }
double CalculateArea()
{
return 0.5 * this.Base * this.Height;
}
}
由于Rectangle
和Triangle
具有CalculateArea
的不同实现,因此它们从基类继承是没有意义的。
如果你创建了一个基类,并且发现只在中包含抽象成员,你也可以只使用一个接口。
并且,正如j__m所述,您不能从多个基类继承,但您可以实现多个接口。
我通常首先定义接口,如果我发现自己在我的实现中复制代码,我会创建一个实现接口的基类,并使我的实现继承它。
答案 1 :(得分:19)
要决定是使用抽象类还是界面,我发现这篇文章非常有用Source:
区分一个或另一个案例的好方法一直是:
是否有许多类可以“组合在一起”并由一个名词描述?如果是这样,请使用此名词的名称创建一个抽象类,并从中继承类。 (一个关键的决定因素是这些类共享功能,你永远不会只实例化动物 ...你总是会实例化某种动物:你的实现动物基类) 示例: Cat 和 Dog 都可以从抽象类 Animal 继承,这个抽象基类将实现一个方法 void Breathe()所有动物都会以完全相同的方式进行。 (我可能会把这个方法变成虚拟的,以便我可以为某些动物覆盖它,比如Fish,它不会像大多数动物一样呼吸)。
- 醇>
什么类型的动词可以应用于我的课程,通常也可以应用于其他人?为每个动词创建一个接口。 示例:所有动物都可以喂食,所以我将创建一个名为 IFeedable 的界面,让Animal实现它。只有 Dog 和 Horse 才能实现 ILikeable - 我不会在基类上实现此功能,因为这不适用于<强>猫强>
请同时查看此Interface vs Base class问题。
答案 2 :(得分:4)
使用抽象类的原因之一是我们必须执行一些初始化(比如通过构造函数的状态)。
接口不允许您定义Constructor的合同。
在下面的示例中,每个Animal对象都应该有一个NAME。这不能通过接口强制执行。
public abstract class Animal
{
public Animal(string name)
{
this.Name = name;
}
public string Name
{
get;
private set;
}
}
public class Cat : Animal
{
public Cat(string name)
: base(name)
{
}
string NoOfLegs { get; set; }
}
class Program
{
static void Main(string[] args)
{
Animal aCat = new Cat("a");
}
}
答案 3 :(得分:3)
实际上它们并不一定是相互排斥的。您可以根据代码实现的演变情况使用它们。
界面通常是合同的发表。它定义了实现者应该遵守的预期行为。对接口编码公共API 通常被认为是一种很好的做法。这样,您可以减少与实现细节的耦合,并允许更轻松地重构和维护代码。现在符合公共API的条件是,软件组件体现了设计中定义的高级交互,并且可以由您自己和其他人在同一个项目内或在独立范围的多个项目中重复使用。
基类已经是实施的一部分。是否实现接口。它将潜在的层次结构与特定的实现细节联系起来:对象状态,可覆盖或不可覆盖的方法等。
答案 4 :(得分:2)
接口是一种更灵活的结构。您只能有一个基类,但可以实现许多接口。如果您需要一个对象来支持多个行为,但这些行为中不止一个需要特定的基类,那么您将无法这样做。
正如Dan所说,基类在许多语言中具有便利性,因为您可以提供基本实现。要使用接口执行此操作,您需要创建一个提供基本实现的类,然后手动将每个接口方法的实现委派给该类 - 这不太方便。
答案 5 :(得分:1)
我在这里找到一个类比有用:
抽象基类: - 汽车制造商可能会开发一种汽油发动机,它有一些变型(1.6,2L等)。引擎块转换可以被认为是抽象基类,即它定义了引擎的基本形状和特征。 2L版本可能有更大的气缸盖等。
<强>接口: - 强> 发动机还可以使用各种现成的部件,例如,交流发电机,散热器,起动电机等,因此必须实现这些组件定义的接口。这些组件通常是在不知道可能使用它们的引擎的情况下设计的。
答案 6 :(得分:0)
如果需要,基本上可以将两者一起使用。但是通常,基类也可以用于继承的类中使用的某些方法或属性。如果创建基类,最好将其抽象;通过在基类中使用虚拟方法,在继承的类中重写它并以不同的方式使用,将比您更灵活。
使用界面,您更加灵活。首先,您需要在从该接口继承的类之间进行声明。有了
Interfaces helps to reduce coupling and therefore allow you to easily interchange implementations for the same concept without the underlying code being affected
您可以更轻松地创建单元测试。
您可以在此处查看this问题以获取更多信息。