这可能是一个通用的OOP问题。我想在接口和抽象类的使用基础上做一个通用的比较。
什么时候需要使用接口,什么时候需要使用抽象类?
这可能是一个通用的OOP问题。我想在接口和抽象类的使用基础上做一个通用的比较。
什么时候需要使用接口,什么时候需要使用抽象类?
当前回答
如果您想提供一些基本实现,请使用抽象类。
其他回答
简单的回答是:抽象类允许您创建子类可以实现或覆盖的功能。接口只允许您定义功能,而不能实现它。虽然一个类只能扩展一个抽象类,但它可以利用多个接口。
我认为最简洁的说法是:
共享属性=>抽象类。 共享功能=>接口。
更简单地说……
抽象类示例:
public abstract class BaseAnimal
{
public int NumberOfLegs { get; set; }
protected BaseAnimal(int numberOfLegs)
{
NumberOfLegs = numberOfLegs;
}
}
public class Dog : BaseAnimal
{
public Dog() : base(4) { }
}
public class Human : BaseAnimal
{
public Human() : base(2) { }
}
由于动物有一个共同的属性——在这种情况下是腿的数量——创建一个包含这个共同属性的抽象类是有意义的。这也允许我们编写操作该属性的通用代码。例如:
public static int CountAllLegs(List<BaseAnimal> animals)
{
int legCount = 0;
foreach (BaseAnimal animal in animals)
{
legCount += animal.NumberOfLegs;
}
return legCount;
}
接口的例子:
public interface IMakeSound
{
void MakeSound();
}
public class Car : IMakeSound
{
public void MakeSound() => Console.WriteLine("Vroom!");
}
public class Vuvuzela : IMakeSound
{
public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");
}
这里要注意的是,呜呜祖拉和汽车是完全不同的东西,但它们有共同的功能:发出声音。因此,接口在这里是有意义的。此外,它将允许程序员将发出声音的东西分组在一个公共界面下——在本例中是IMakeSound。通过这种设计,你可以编写以下代码:
List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());
foreach (IMakeSound soundMaker in soundMakers)
{
soundMaker.MakeSound();
}
你知道那会输出什么吗?
最后,您可以将两者结合起来。
结合例子:
public interface IMakeSound
{
void MakeSound();
}
public abstract class BaseAnimal : IMakeSound
{
public int NumberOfLegs { get; set; }
protected BaseAnimal(int numberOfLegs)
{
NumberOfLegs = numberOfLegs;
}
public abstract void MakeSound();
}
public class Cat : BaseAnimal
{
public Cat() : base(4) { }
public override void MakeSound() => Console.WriteLine("Meow!");
}
public class Human : BaseAnimal
{
public Human() : base(2) { }
public override void MakeSound() => Console.WriteLine("Hello, world!");
}
这里,我们要求所有的BaseAnimals发出声音,但是我们还不知道它的实现。在这种情况下,我们可以抽象接口实现并将其实现委托给它的子类。
最后一点,还记得在抽象类示例中我们如何操作不同对象的共享属性,以及在接口示例中我们如何调用不同对象的共享功能吗?在最后一个例子中,我们可以两者都做。
如果下列语句适用于您的情况,请考虑使用抽象类:
您希望在几个密切相关的类之间共享代码。 您希望扩展抽象类的类具有许多公共方法或字段,或者需要除public以外的访问修饰符(例如protected和private)。 您希望声明非静态或非final字段。这使您能够定义可以访问和修改其所属对象状态的方法。
如果这些语句适用于您的情况,请考虑使用接口:
您希望不相关的类实现您的接口。例如,Comparable和Cloneable接口是由许多不相关的类实现的。 您希望指定特定数据类型的行为,但不关心由谁实现其行为。 您希望利用多个继承。
源
对我来说,在很多情况下我会选择接口。但在某些情况下,我更喜欢抽象类。
OO中的类通常指的是实现。当我想强制一些实现细节到子程序时,我使用抽象类,否则我就使用接口。
当然,抽象类不仅在强制实现方面有用,而且在许多相关类之间共享一些特定的细节方面也有用。
基本的经验法则是:对于“名词”使用抽象类,对于“动词”使用接口
例如:car是一个抽象类和驱动器,我们可以让它成为一个接口。