Нулевой объектный образец Фаулера: зачем использовать наследование?

Почему Фаулер PoEAA р. 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;}
}

В целом я нашел все примеры Фаулера хорошо продуманными, и, должно быть, я кое-что здесь упустил.

4 ответа

Решение

Причиной наследования является переопределение поведения класса. То, как вы думаете об этом, мне кажется, что вы собираетесь проверить, равен ли объект, который у вас есть, NullCustomer статический экземпляр, чтобы принять решение, однако цель нулевого объекта - поддержать принцип подстановки Лискова.

Другими словами, вы используете нулевой объект для установки ссылки, и у вас не будет специальной проверки для него, вы просто будете использовать его, и у него должно быть другое поведение (на самом деле это отсутствие поведения).

Проблема вашего второго примера с магическим значением состоит в том, что если в вашем классе есть другие предметы, которые являются частью класса, теперь вам нужно вставить проверки против магии, чтобы принять решение о возврате информации или какой-либо другой соответствующей информации.

С классом Null класс возвращает то, что наиболее целесообразно, без таких проверок.

Например, класс клиента может вернуть общие долларовые затраты этого пользователя после соответствующего запроса к БД. А NullCustomer просто сможет return 0;, С магическим значением он либо получит информацию для фиктивного пользователя из БД, либо должен будет выполнить другую конкретную проверку, прежде чем делать разумную вещь.

Добавление к тому, что сказал Чап. Шаблон Null Object используется для того, чтобы по умолчанию был допустимый набор значений. Кроме того, если вы попытаетесь использовать NullCustomer в MVC, вы все равно сможете получить доступ к объекту, представляющему модель, вместо того, чтобы учитывать потенциальные несуществующие данные. [проверка на нули]

Я не программист на C#, но похоже, что во втором примере вы можете сделать эквивалент:

Customer.NullCustomer.Name = "Not Null";

В общем, объекты имеют поведение, а не только данные, поэтому все становится сложнее.

Другие вопросы по тегам