从类或抽象类继承

时间:2009-03-02 19:35:08

标签: c# .net inheritance class

如果你有几个类希望它们从基类继承以获得通用功能,那么你应该使用类或抽象类来实现基类吗?

11 个答案:

答案 0 :(得分:39)

这取决于,如果您永远不希望能够实例化基类,那么将其设为抽象。否则将其保留为普通班级。

答案 1 :(得分:16)

如果基类不应该被实例化,那么使它成为一个抽象类 - 如果基类需要实例化,那么不要使它抽象。

在这个例子中,使基类抽象是有意义的,因为基类没有任何具体含义:

abstract class WritingImplement
{
    public abstract void Write();
}

class Pencil : WritingImplement
{
    public override void Write() { }
}

但是在下一个示例中,您可以看到基类如何具有具体含义:

class Dog
{
    public virtual void Bark() { }
}

class GoldenRetriever : Dog
{
    public override void Bark() { }
}

这一切都非常主观 - 你应该能够根据你特定领域的需求做出相当不错的判断。

答案 2 :(得分:6)

这取决于,有问题的基类是否有意义存在于它自己而不是从中派生出来?如果答案是肯定的,那么它应该是一个普通的类,否则,它应该是一个抽象类。

答案 3 :(得分:4)

我建议:

  • 制作界面。
  • 在基类中实现接口。
  • 使基类成为真正的类,而不是抽象类(请参阅下面的原因)。

我更喜欢真正的类而不是抽象类的原因是抽象类无法实例化,这限制了未来的选项不必要的。例如,稍后我可能需要基类提供的状态和方法但不能继承而不需要实现接口;如果基类是抽象的我运气不好,但如果基类是常规类,那么我可以创建基类的实例并将其作为我的其他类的一个组件,并委托给实例重用提供的州/方法。

是的,这不会经常发生,但关键是:当没有理由这样做时,使基类抽象可以防止这种重用/解决方案。

现在,如果实例化基类会以某种方式危险,那么将其抽象化 - 或者最好使其不那么危险,如果可能的话; - )

答案 4 :(得分:3)

将其视为银行帐户:

您可以创建一个名为“帐户”的通用抽象基本帐户,它包含客户详细信息等基本信息。

然后,您可以创建两个名为“SavingAccount”或“DebitAccount”的派生类,这些类可以拥有自己的特定行为,同时受益于基类行为。

在这种情况下,客户必须拥有储蓄账户或借记账户,不允许使用通用的“账户”,因为在现实世界中仅仅拥有一个没有描述的账户并不是很受欢迎。

如果您可以根据需要创建类似的场景,那么抽象是可行的方法。

答案 5 :(得分:1)

抽象类用于部分实现的类。

拥有抽象类的实例本身没有意义,需要派生它。如果您希望能够创建基类,则它不能是抽象的。

我喜欢将抽象类视为具有预定义某些成员的接口,因为它们对所有子类都是通用的。

答案 6 :(得分:1)

以不同的方式思考

  

我的基类是否是它自己的完整对象?

如果答案是否定的,则将其抽象化。如果是,那么你可能想把它变成一个具体的类。

答案 7 :(得分:0)

我想说如果你不打算单独调用基类,那么你应该将它定义为抽象类。

答案 8 :(得分:0)

取决于您是否希望基类自行实现。

作为一个抽象类,你不能从中创建对象。

答案 9 :(得分:0)

抽象类非常适合预定义的功能,例如 - 当知道类应该公开的最小确切行为但不知道应该使用什么数据来执行它或确切的实现。

abstract class ADataAccess
{
    abstract public void Save();
}

普通(非抽象)类可以用于类似的事情,但你必须知道能够编写它们的实现细节。

public class DataAccess
{
    public void Save()
    {
        if ( _is_new )
        {
            Insert();
        }
        else if ( _is_modified )
        {
            Update();
        }
    }
}

此外,您可以使用接口(单独或在类上,无论是否抽象)来定义相同类型的原型定义。

interface ISaveable
{
    void Save();
    void Insert();
    void Update();
}

class UserAccount : ISavable
{
    void ISavable.Save() { ... }
    void ISavable.Insert() { ... }
    void ISavable.Update() { ... }
}

另一种选择可能是使用泛型

class GenDataAccess<T>
{
    public void Save()
    {
        ...
    }
}

所有这些方法都可用于为要使用的类定义某个原型。如何确保代码A可以与代码B交谈。当然,您可以根据自己的喜好混合和匹配以上所有内容。没有明确的正确方法,但我喜欢定义接口和抽象类,然后参考接口。这样就消除了更高级别的“管道”的一些思想要求,同时保持了最大的灵活性。 (让接口消除了使用抽象基类的要求,但将其留作选项)。

答案 10 :(得分:-7)

我认为很多人应该再次重新启用基本的OO课程。

OOA / OOD的基本原理是抽象抽象抽象,直到你不能抽象为止。如果你所看到的是一个抽象,那就这样吧,那就是你的OOA / OOD告诉你的。但是,如果你坐在那里想知道“代码”是否应该是抽象的,那么你显然不知道该术语的含义,应该再次学习基本的OOA / OOD / OOP: - )

更重要的是,您应该学习设计模式和谐波理论,这将极大地帮助您的OO设计!