这可能是一个通用的OOP问题。我想在接口和抽象类的使用基础上做一个通用的比较。

什么时候需要使用接口,什么时候需要使用抽象类?


当前回答

对我来说,在很多情况下我会选择接口。但在某些情况下,我更喜欢抽象类。

OO中的类通常指的是实现。当我想强制一些实现细节到子程序时,我使用抽象类,否则我就使用接口。

当然,抽象类不仅在强制实现方面有用,而且在许多相关类之间共享一些特定的细节方面也有用。

其他回答

我认为最简洁的说法是:

共享属性=>抽象类。 共享功能=>接口。

更简单地说……

抽象类示例:

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发出声音,但是我们还不知道它的实现。在这种情况下,我们可以抽象接口实现并将其实现委托给它的子类。

最后一点,还记得在抽象类示例中我们如何操作不同对象的共享属性,以及在接口示例中我们如何调用不同对象的共享功能吗?在最后一个例子中,我们可以两者都做。

什么时候做什么是一件非常简单的事情,如果你有清晰的概念在你的脑海里。

抽象类可以是派生类,而接口可以是实现类。这两者之间有一些区别。当派生抽象类时,派生类和基类之间的关系是“is a”关系。例如,狗是动物,羊是动物,这意味着派生类从基类继承了一些属性。

而对于接口的实现,关系是“可以是”。例:狗可以是间谍犬。狗可以是马戏团的狗。狗可以是比赛犬。这意味着你要实现特定的方法来获取某些东西。

我希望我讲清楚了。

如果您想提供一些基本实现,请使用抽象类。

两者都是类定义的契约:

结论1:两种意图都是对象泛化

在定义抽象类时,它们也可以有默认实现。

结论2:区分存在于行为泛化设计中

在使用抽象类时,类只能从一个抽象类继承

结论3:抽象类在应用上存在局限性。它的意思是 行为概括的局限性。

最后结论-何时使用哪个:区分是在行为泛化层面

在类的行为设计中,如果功能在确定的类之间只是概念上的限制,换句话说,在确定的类之间是共享的,则使用抽象类。但如果功能比确定类更通用,或者我们可以/想要向其他类添加功能,则使用接口作为契约。

对我来说,在很多情况下我会选择接口。但在某些情况下,我更喜欢抽象类。

OO中的类通常指的是实现。当我想强制一些实现细节到子程序时,我使用抽象类,否则我就使用接口。

当然,抽象类不仅在强制实现方面有用,而且在许多相关类之间共享一些特定的细节方面也有用。