【发布时间】:2010-10-10 20:37:59
【问题描述】:
如果您有几个类希望它们从基类继承以实现通用功能,您应该使用类还是抽象类来实现基类?
【问题讨论】:
标签: c# .net inheritance class
如果您有几个类希望它们从基类继承以实现通用功能,您应该使用类还是抽象类来实现基类?
【问题讨论】:
标签: c# .net inheritance class
我建议:
我更喜欢真实类而不是抽象类的原因是抽象类不能被实例化,这限制了未来的选择不必要地。比如以后可能需要基类提供的状态和方法,但是不能继承,不需要实现接口;如果基类是抽象的,我很不走运,但如果基类是常规类,那么我可以创建基类的实例并将其作为我的另一个类的组件,并委托给实例以重用提供的状态/方法。
是的,这并不经常发生,但重点是:当没有理由这样做时,将基类抽象化可以防止这种重用/解决方案。
现在,如果实例化基类在某种程度上是危险的,那么将其抽象化 - 或者如果可能的话,最好降低它的危险性;-)
【讨论】:
抽象类非常适合预定义的功能,例如 - 当知道一个类应该公开的最小确切行为但不知道它应该使用什么数据或确切实现时。
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 对话的方法。当然,您可以根据自己的喜好混合搭配以上所有内容。没有明确的正确方法,但我喜欢定义接口和抽象类,然后引用接口。这种方式消除了在更高级别课程中“管道”的一些思想要求,同时保持最大的灵活性。 (拥有接口消除了使用抽象基类的要求,但将其作为一种选择)。
【讨论】:
我认为你们中的很多人应该重新学习基本的 OO 课程。
OOA/OOD 的基本原理是抽象抽象,直到不能抽象为止。如果你看到的是一个抽象,那就这样吧,这就是你的 OOA/OOD 已经告诉你的。但是,如果您坐在那里想知道“代码”是否应该是抽象的,那么您显然不知道该术语的含义,并且应该再次学习基本的 OOA/OOD/OOP :-)
更重要的是,您应该学习设计模式和调和理论,这将极大地帮助您的 OO 设计!
【讨论】:
把它想象成一个银行账户:
您可以创建一个名为“Account”的通用抽象基本帐户,其中包含客户详细信息等基本信息。
然后,您可以创建两个名为“SavingAccount”或“DebitAccount”的派生类,它们可以有自己的特定行为,同时受益于基类行为。
在这种情况下,客户必须拥有储蓄账户或借记账户,不允许使用通用“账户”,因为在现实世界中只有一个没有描述的账户并不流行。
如果您可以根据自己的需要创建类似的场景,那么抽象就是您要走的路。
【讨论】:
换个角度想一下
我的基类本身是一个完整的对象吗?
如果答案是否定的,则将其抽象化。如果是,那么您可能希望将其设为具体类。
【讨论】:
抽象类用于部分实现的类。
拥有抽象类的实例本身没有意义,它需要派生。如果您希望能够创建基类,则它不能是抽象的。
我喜欢将抽象类视为具有一些预定义成员的接口,因为它们对所有子类都是通用的。
【讨论】:
如果不应该实例化基类,则将其设为抽象类 - 如果需要实例化基类,则不要将其设为抽象类。
在这个例子中,使基类抽象是有意义的,因为基类没有任何具体含义:
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() { }
}
这真的很主观 - 你应该能够根据你的特定领域的需求做出很好的判断。
【讨论】:
这取决于,有问题的基类独立存在而不派生于它是否有意义?如果答案是肯定的,那么它应该是一个常规类,否则它应该是一个抽象类。
【讨论】:
这取决于您是否希望基类自己实现。
作为一个抽象类,你不能用它来制造对象。
【讨论】:
如果你不打算自己调用基类,那么你应该将它定义为抽象类。
【讨论】:
这取决于,如果您永远不希望能够实例化基类,那么将其抽象化。否则将其保留为普通类。
【讨论】: