如何为新实现决定是使用接口还是基类
本文关键字:接口 基类 决定 新实现 实现 | 更新日期: 2023-09-27 18:05:20
当涉及到实现时,我应该如何决定使用基类型还是接口?我试着用几个例子来解决问题,但我没有得到完整的想法:(
关于如何和为什么……的例子将不胜感激。基类,无论是否抽象,都可以包含已实现的成员。接口不能。如果您的所有实现都将执行类似的操作,则可以使用基类,因为您的所有子类都可以共享基类上成员的相同实现。如果他们不打算共享实现,那么接口可能是一种方法。
的例子:
class Person
{
string Name { get; set; }
}
class Employee : Person
{
string Company { get; set; }
}
从Person继承Employee是有意义的,因为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所说,你不能从多个基类继承,但是你可以实现多个接口。
我通常首先定义接口,如果我发现自己在实现中重复代码,我创建一个实现接口的基类,并使我的实现继承它。
要决定是使用抽象类还是接口,我发现这篇文章非常有帮助。
对我来说,区分一种情况或另一种情况的好方法一直是:
是否有许多类可以"分组在一起"并用一个名词来描述?如果是,用这个名词的名字创建一个抽象类,并从它继承这些类。(关键的决定因素是这些类共享功能,您永远不会实例化一个Animal…你总是会实例化某种类型的Animal:你的Animal基类的实现)示例: Cat和Dog都可以继承抽象类Animal,并且这个抽象基类将实现一个方法void Breathe(),因此所有动物都将以完全相同的方式执行该方法。(我可能会把这个方法设为虚拟的,这样我就可以对某些动物重写它,比如鱼,它不像大多数动物那样呼吸)。
哪些动词可以应用于我的班级,而通常也可以应用于其他人?为每个谓词创建一个接口。示例:所有动物都可以喂食,所以我将创建一个名为IFeedable的接口,并让Animal实现它。只有Dog和Horse可以很好地实现ILikeable -我不会在基类上实现这一点,因为这不适用于Cat。
也请看看这个接口与基类的问题。
使用抽象类的原因之一是我们必须强制一些初始化(如通过构造函数的状态)。
Interface不允许定义构造函数的契约。
在下面的例子中,每个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");
}
}
实际上它们并不一定是互斥的。您可以根据代码实现的发展方式来使用这两种方法。
接口通常是对合同的表述。它定义了实现者应该遵守的预期行为。根据接口编写公共api通常被认为是一个很好的实践。这样就减少了对实现细节的耦合,并允许更容易地重构和维护代码。现在,被称为公共api的是包含在您的设计中定义的高级交互的软件组件,它们可以被您自己和同一项目中的其他人或独立范围的几个项目中的其他人重用。
基类已经是实现的一部分。它是否实现了一个接口。如果它将潜在的层次结构与特定的实现细节联系起来:对象状态,可重写或不可重写的方法,等等
接口是一种更灵活的结构。您只能有一个基类,但可以实现许多接口。如果你需要一个对象来支持多个行为,但是其中一个以上的行为需要一个特定的基类,那么你将无法做到这一点。
正如Dan所指出的,基类在许多语言中都具有便利的优势,因为您可以提供基实现。要使用接口做到这一点,需要创建一个提供基实现的类,然后手动将每个接口方法的实现委托给该类——这并不那么方便。
我发现这里有一个类比很有帮助:
抽象基类:汽车制造商可能会开发一种汽油发动机,它有一些变种(1.6升,21升等)。发动机缸体铸件可以被认为是抽象基类,即它定义了发动机的基本形状和特征。一个2L的版本可能有一个更大的气缸盖等。
接口:- 发动机也可能使用各种现成的组件,例如交流发电机、散热器、启动电机等,因此它必须实现由这些组件定义的接口。这些部件通常是在不了解可能使用它们的发动机的情况下设计的。
如果需要,基本上可以将两者同时使用。但通常基类也可以用于继承类中使用的一些方法或属性。如果你创建一个基类,最好是抽象的;在基类中使用虚方法,在继承的类中重写它,并以不同的方式使用,这样会更灵活。
使用接口,您将更加灵活。首先,在从这个接口继承的类之间做一个声明。这个
-
让你的代码更容易读
-
你分离你的概念,就像从接口a继承的类可以连接Mssql数据库,但另一个可以连接Mysql数据库。
-
你的代码变得更易于维护;
Interfaces helps to reduce coupling and therefore allow you to easily interchange implementations for the same concept without the underlying code being affected
-
你可以使用依赖注入
-
您可以更轻松地创建unittest。
你可以在这里查看这个问题以获得更多信息。