Нулевой объектный образец Фаулера: зачем использовать наследование?
Почему Фаулер 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
используется в качестве интерфейса маркера. Мне не очень нравится этот подход по трем причинам:
- Свойства должны быть помечены как виртуальные
- Я больше не могу запечатать свои классы сущностей
- По крайней мере (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";
В общем, объекты имеют поведение, а не только данные, поэтому все становится сложнее.