【问题标题】:Empty Derived Classes Vs Type Property空派生类与类型属性
【发布时间】:2016-09-20 19:23:35
【问题描述】:

我无法确定下面这两个示例的优缺点。理想情况下,我想知道哪种设计最重要:

示例 1(类型属性):

public abstract class Animal : /* all relevant interfaces*/
{
    /*
    All necessary implementations
    */
}

Public class Dog : Animal
{
    Public string Name {get; set;}
    Public Breed Type {get; set;}

    /* 
    All necessary implementations
    */
}

Public Type Breed
{
    Bulldog,
    Chihuahua,
    Labrador,
    /*
    So on……
    This can grow without limitation, 
    you dno't know how much it will grow into, or 
    what breed you will have tomorrow e.g BulldogChihuahuaCross, 
    or BulldogLabradorCross.
    */
}

示例 2(空派生类):

public abstract class Animal : /* all relevant interfaces*/
{
    /*
    All necessary implementations
    */
}

Public class Dog : Animal
{
    Public string Name {get; set;}

    /* 
    All necessary implementations
    */
}

Public class Bulldog : Dog
{
   /* Empty Class */
}

Public class Chihuahua: Dog
{
   /* Empty Class */
}

Public class Labrador: Dog
{
   /* Empty Class */
}

编辑:

在示例 1 中,创建了 Dog 的实例并将其类型分配为属性,在示例 2 中,创建了该特定类型的实例。

我正在寻找一些深入的论点、可扩展性、可维护性、如果有 1000 种品种的 CPU 成本、运行查询的成本等。

【问题讨论】:

  • 这其实是一个很好的问题,大多数人都懒得问。我有一个我认为对你来说很好的答案,但是直到今天晚些时候才有时间正确地写出来。敬请期待。
  • @JimL。期待您的回答。
  • @JimL。或者就像费马说的:我有一个很好的证明,但是这里的空白太窄了,不能写下来;-)
  • @ThomasKilian 我不会拒绝听你的意见:)。

标签: architecture uml


【解决方案1】:

频谱上有两个极端。一方面是一组仅提供信息的事物,并作为文本、数字或对枚举实例的引用进行操作。例如,狗沙龙应用程序可能会记录您宠物的名字、颜色和品种,仅作为文本用于识别目的。在频谱的另一端是需要具有不同属性、操作或方法的事物集。例如,视频游戏可能希望在每种狗吠叫时发出不同的声音。

作为设计师,必须做出的决定是如何准确地反映“话语领域”以及何时为特定应用程序走捷径。在话语领域,每个品种都有使其独特的特征,但对于狗沙龙应用程序的目的,你根本不在乎。在这种情况下,您可以设计掉细节并希望您将来永远不需要它。

问题在于该范围的中间,即有人做出了错误的决定。我曾在大型企业系统上工作,其中有人将继承层次结构压缩为明确编码为一个或多个数据库列中的值的类型。这太可怕了,因为程序员的问题是要知道哪些其他列对每种编码类型有效。该系统到处都有 switch 语句来实现业务规则,这些规则随着时间的推移演变成非常复杂的东西。系统有很多bug。

出于这个原因,在光谱的中间,事情不是那么清楚,我会犯许多类的错误。原因是准确反映领域可以更容易判断是否满足要求,并且可以使代码更直观地维护(假设它是DDD)。反映领域的关键是准确地表示事物的集合。例如,“Fido”是 Dog 集和 Animal 超集的成员; “西尔维斯特”是猫集和动物超集的成员。这对人们来说很容易理解,每个类都可以有不同的实现,对外隐藏。一旦您开始解释显式编码为字符串、整数或枚举字面量引用的类型,您就会开始到处需要 switch 语句,并且您会遇到无法维护、难以理解的混乱局面。许多 OO 语言可以让您摆脱这一切,但您必须创建一个包含完整类型列表的工厂。运行时开销可以忽略不计(特别是如果您实现工厂以恒定时间运行),并且类型可以映射到关系数据库中的值,以便您可以查询和报告它们。此外,正如您所指出的,您也许可以利用泛型。

如果您知道您的课程将永远是空的,就像狗沙龙申请中的情况一样,请不要打扰课程。如果您知道它们会有不同的属性、操作和方法,或者如果您不确定,请使用类。

【讨论】:

  • 谢谢吉姆。这正是我的问题,我给出的例子比我实际的例子简单得多。我正在开发一个非常复杂的企业系统。它使用“事件溯源”和 DAG(有向无环图),因此系统有两部分,第一部分创建对象的实例,第二部分,这些对象注册到依赖于大量使用泛型的事件溯源。为了适应泛型的使用,随着时间的推移,空类已经接管了。
  • 虽然,在项目开始的时候,还有很多不为人知的事情,但现在,已经有些尘埃落定了。我的问题是值得从话语领域转移,同时我想小心它不应该像 switch 语句或 if 无处不在那样以大混乱结束。
  • 为什么此时要冒险更改为枚举?我指出了未来可能出现的恶劣情况。我不认为课程有真正的缺点,只是它们很烦人。
【解决方案2】:

第一种方法可以让您确定狗是哪个品种,但第二种方法可以让您为子类进行特定的实现。

如果您需要对象为每种不同的狗品种具有不同的方法或属性,请使用派生类,否则只具有类型属性和单个类会更简单。

【讨论】:

【解决方案3】:

好的,这是我的 2 美分:如果您正在寻找对任何东西的快速访问,您可以将它放在关联数组中。您的两个实现都提供了一个要使用的哈希码(作为对象地址),这使得它们可以以相同的速度访问。仅当您打算添加功能时,子类化(基本上)才有意义。从分类器中获取类型与从枚举中获取类型没有什么不同。如果您需要智能查询,请创建一个智能关联数组。

【讨论】:

  • 这是一个很好的观点。我正在尝试将一种方式从空子类转移到类型列表,但我想确保不会在设计中造成混乱。
  • 在设计方面(如前所述)枚举是更好的选择,因为您只创建用于打字的子类,而不是添加真正目的的功能。
猜你喜欢
  • 2014-06-27
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多