Возможно ли создать NullObject для каждого класса? (с инструментом, конечно) - PullRequest
4 голосов
/ 16 июля 2010

NullObjectPattern предназначен для "безопасного" (нейтрального) поведения.

Идея состоит в том, чтобы создать объект, который ничего не делает (но также не генерирует исключение NullPointerException)

Например, класс, определенный как:

class Employee {
    private String name;
    private int age;
    public String getName(){ return name; }
    public int getAge()    { return age;  }
}  

Будетвызвать исключение NullPointerException в этом коде:

 class Other {
      Employee oscar;

      String theName = oscar.getName(); // NPE

 }

Что говорит NOP, так это то, что у вас может быть объект, подобный этому:

 class NullEmployee extends Employee {
      public static final  Employee instance = new NullEmployee(); 
      public String getName(){ return ""; }
      public int getAge()    { return 0;  }
 }

И затем используйте его в качестве значения по умолчанию.

 Employee oscar = NullEmployee.instance;

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

Было бы целесообразно / разумно / полезно создать такой инструмент или использовать его (если он существует)?

Возможно, при использовании AOP или DI значение по умолчанию можно было бы использовать автоматически.

Ответы [ 6 ]

3 голосов
/ 19 июля 2010

Для меня паттерн Null Object выглядит как плацебо. Реальный объект и нулевой объект могут иметь совершенно разные значения, но действовать очень похоже. Как и плацебо, нулевой объект заставит вас поверить, что в этом нет ничего плохого, но что-то может быть очень неправильным.

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

Из статьи Википедии :

Преимущество этого подхода перед работающей реализацией по умолчанию состоит в том, что нулевой объект очень предсказуем и не имеет побочных эффектов: он ничего не делает .

Это также не будет указывать на проблемы . Подумайте, что произойдет, когда нулевой объект пройдет весь путь через ваше приложение. Затем в какой-то момент ваше приложение ожидает от объекта определенного поведения, которое не может быть реализовано реализацией нулевого объекта. В этот момент ваше приложение может аварийно завершить работу или войти в недопустимое состояние. Вам будет очень трудно отследить происхождение нулевого объекта . null указатель вызвал бы исключение в самом начале, обратив ваше внимание непосредственно на источник проблемы.

Единственный пример, который приводит статья в Википедии, - это пустая коллекция вместо null. Это очень хорошая практика, но паршивый пример шаблона нулевого объекта, потому что он имеет дело с коллекцией объектов, а не с одним экземпляром.

Короче говоря, я уверен, что возможно создать реализации нулевых объектов для всех ваших классов, но я настоятельно рекомендую против этого.

2 голосов
/ 16 июля 2010

Я думаю, вы просто просите выдвинуть условия ошибки в слой.

Когда приложение запрашивает объект, и он является нулевым, вам нужно иметь дело с этим условием, а не просто надеяться, что оно в порядке. Если объект имеет значение null и вы пытаетесь использовать его, вы получите ошибки, так зачем делать всю эту проверку ошибок для остальной части кода?

2 голосов
/ 16 июля 2010

Я не уверен, что это хорошая идея. «NullObject» может быть полезен и в некоторых случаях имеет смысл, но иметь это для каждого класса - излишнее. Тем более что это потенциально может затруднить диагностику некоторой ошибки (или пробелов в анализе).

Кроме того, как насчет библиотек третьей части, которые возвращают новые объекты? Не могли бы вы поставить какой-то «интерфейс» перед ними, чтобы в случае, если они возвращают ноль, вы заменили аппетитную разновидность нуль-объекта?

Вы упомянули, что пытаетесь автоматизировать это - не потребует ли в некоторых случаях фактическое проектное решение для возврата подходящего значения? Т.е. предположим, что у вас есть объект Image, и он возвращает «ImageType» (перечисление для .gif, .jpg и т. Д.)

В этом случае ImageNullObject должен вернуть ... "IMAGETYPE.GIF"? "IMAGETYPE.UNKNOWN"? Null?

0 голосов
/ 14 декабря 2010

То, что я хотел бы видеть, это чтобы компилятор позволял определять поведение нулевого объекта со статически определенным типом.Например, если 'Foo' относится к классу 'bar':

Class Bar
  Dim Value as Integer
  Function Boz() As Integer
    Return Value
  End Sub
  Sub Nothing.Bar() As Integer
    Return -9
  End Sub
End Class

, попытка оценить Foo.Bar () выдаст Foo.Value, если Foo не равен нулю, или -9.Можно достичь такой функциональности, используя методы расширения, но это выглядит немного странно.

0 голосов
/ 23 июля 2010

За исключением тестирования, я обычно называю этот тип концептуального кодирования для Slop. Это противоположность отказоустойчивости: вы откладываете любой шанс найти состояние, для которого вы не кодировали.

Суть в том, почему ваш объект может возвращать значение, которого нет в контракте метода? Когда вы разрабатывали и кодировали контракт метода, вы или говорили, что он может или не может вернуть ноль, верно? Так что, если вы можете вернуть null, это важно. Если вы не можете вернуть ноль, это важно.

Кроме того, если ссылка на объект, которую вы используете, может быть нулевой, это значимое значение, и вы НИКОГДА не должны погружаться в код, который может получить доступ к методам этого объекта.

Кроме того, используйте окончательные / постоянные / инвариантные переменные при каждой возможности, которую вы получаете, и (по крайней мере, в ОО-языках изолируйте ваши данные от конструктора, который может обеспечить правильное состояние). Если неизменный объект правильно устанавливает свои переменные, эти переменные не могут возвращать недопустимые значения.

За исключением экстренных патчей и тестирования, я, честно говоря, не вижу никаких оправданий для такого рода кодирования, кроме "Я не понимаю код и думаю, что он работает неправильно, но я не хочу пытаться понять это "- что, IMO, не является оправданием для инженера.

0 голосов
/ 16 июля 2010

Я думаю, было бы сложно автоматически сгенерировать функциональные нулевые объекты.(Конечно, вы могли бы создать оболочки, которые затем пошли бы и заполнить саму реализацию).

В качестве быстрого примера - какова нулевая функциональность для метода, который возвращает int?Должен ли он возвращать -1, 0 или, возможно, какое-то другое значение?Как насчет того, что возвращает строку - опять же, null или "" правильный выбор?Для методов, возвращающих какой-то другой класс - если это один из ваших собственных классов, то, вероятно, вы могли бы использовать Null Object для этого класса, но как бы вы получили к нему доступ?Возможно, вы могли бы заставить каждый класс, который вы пишете, реализовывать некоторый интерфейс с аксессором для нулевого объекта, но стоит ли это того?

Даже с методами, которые возвращают void, не всегда так, чтобы нулевая функциональность былапросто вернуться.Например, некоторым классам может потребоваться вызвать метод для родительского / делегатского объекта, когда они сделали свое дело (что в данном случае будет неактивным), чтобы сохранить инварианты.класса.

Таким образом, в основном - даже для реализации "нулевого" поведения, вы должны быть в состоянии вывести, каково это поведение, и я ожидаю, что это слишком продвинуто для того, чтобы инструмент сам себя сделал.Возможно, вы могли бы аннотировать все ваши методы чем-то вроде @NullReturns(-1), и иметь инструмент, подобрать их и сформировать реализацию нулевого объекта, но даже это не будет охватывать каждую ситуацию, и вы также можете написать объект напрямую, а не писать всеего функциональность в аннотациях.

...