【问题标题】:Fowler Null Object Pattern: Why use inheritance?Fowler 空对象模式:为什么要使用继承?
【发布时间】:2009-11-10 17:42:14
【问题描述】:

为什么 Fowler PoEAA p. 498 用以下方式定义空对象模式(示例缩短,语言是c#但没关系):

public class Customer
{
  public virtual string Name {get; set;}
}

public class NullCustomer : Customer, INull
{
  public override Name 
  {
     get { return "ImTheNull";}
     // setter ommitted
  }
}

INull 用作标记接口。 我不太喜欢这种方法,原因有以下三个:

  1. 属性需要标记为虚拟
  2. 我不能再密封我的实体类了
  3. 至少引入了 (n+1) 个新类型(n 个空对象,一个标记接口)

为什么不这样实现:

public class Customer
{
  public static readonly Customer NullCustomer = new Customer(){Name = "ImtTheNullCustomer";}

  public string Name {get; set;}
}

我普遍认为所有 Fowlers 的例子都经过深思熟虑,显然我在这里错过了一些东西。

【问题讨论】:

  • 不要将方法设为虚拟,或出于这个原因让类处于未密封状态。虽然我非常尊重 Martin Fowler,但在他的许多涉及继承的示例中都存在明显的 Java 偏见。在 Java 中,方法默认是虚拟的。在 C# 中它们不是,并且该设计决策是专门由于默认虚拟方法的感知问题而做出的。无论如何,如果 NullCustomer 是有效客户,请使用此模式。一个好的指标是将其与空列表进行比较。一个空列表是一个非常好的列表,并且传播它没有害处。这可能不是这里的情况。

标签: design-patterns null-object-pattern poeaa


【解决方案1】:

继承的原因是为了重写类的行为。在我看来,您正在考虑的方式就像您要检查您拥有的对象是否等于 NullCustomer 静态实例以做出决定,但是空对象的重点是维护 Liskov's substitution principle

换句话说,您使用 null 对象来设置引用,并且您不会对其进行特殊检查,您只会使用它并且它应该具有不同的行为(实际上是缺乏行为)。

【讨论】:

  • 你打错了 Liskov 的名字。
  • 好的,所以问题在于方法(计算等)而不是简单的获取设置属性? (对 Alister 的同样问题)
  • 是的,行为在方法甚至属性中。请注意,在您的示例中,空对象中缺少 setter。这改变了基类的行为,其中 null 对象是只读的。
  • setter 被省略只是为了缩短代码,但你是对的,空对象无论如何都应该是不可变的。无论如何,我不喜欢具有可观察到的副作用的属性,但感谢您的澄清。
【解决方案2】:

你的第二个例子的问题是,如果你的类有其他项目是类的一部分,你现在必须插入对魔法的检查来决定返回信息,或者一些其他适当的信息.

对于 Null 类,该类返回最有意义的内容,而无需进行此类检查。

例如,在适当地询问数据库之后,客户类可能会返回该用户的总美元支出。 NullCustomer 只能return 0;。有了这个神奇的值,它要么从数据库中为一个虚拟用户获取信息,要么在做有意义的事情之前必须运行另一个特定的检查。

【讨论】:

  • 好的,所以问题在于方法(计算等)而不是简单的获取设置属性。
  • 0 是正确的默认值吗?这取决于你想要做什么。您不想将 NullCustomer 插入到您的数据库中...
【解决方案3】:

补充 Chap 所说的话。使用空对象模式,以便有一组可接受的默认值。此外,如果您尝试在 MVC 中使用 NullCustomer,您仍然可以访问表示模型的对象,而不必考虑潜在的不存在数据。 [检查空值]

【讨论】:

    【解决方案4】:

    我不是 C# 程序员,但在您的第二个示例中,您可以执行以下操作:

    Customer.NullCustomer.Name = "Not Null";
    

    一般来说,对象有行为,而不仅仅是数据,所以它变得更加复杂。

    【讨论】:

    • 是的,你没看错,不过其他人已经提到过。无论如何感谢您的评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 2010-12-07
    • 2011-04-30
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多