пятница, 17 сентября 2010 г.

Null Object и проблемы, которые он может принести

У Степанова в его лекциях по программированию мимоходом рассказывается о проблеме, которую привносит в template algorithm'ы STL'я и в обобщённое программирование на C++, требование IEEE стандарта к наличию специального значения в диапазонах double/float( NaN - Not a Number).

Подробности можно прочитать в Notes from the lectures of Programming by Alexandr Stepanov, но суть проблемы следующая:

Любая операция сравнения, которая выполняется с NaN, должна возвращать false. Такое требование закладывает мину практически во все алгоритмы из библиотеки STL, которые опираются на операции сравнения.

Степанов заявляет, что так как это случай редкий и касается только 1 типа, то можно его проигнорировать. Но здесь на сцену выходят Фаулер и Кириевски с их идеей рефакторинга "Introduce Null Object", и мы по сути получаем проблему, которую Степанов считал малозначащей, только перенесённую уже и в другие языки программирования, а не только на C++.

Дальше чуть более подробно мои размышления на эту тему...

С одной стороны, моя архитекторская жилка говорит, что идея с Null Object довольно здравая (ну, по крайней мере удобная) - создать подтип, который реализует нужный интерфейс с методами заглушками и поведением по умолчанию, а в нужный момент просто заменять объект на реальный.
Но с другой стороны, оценив риск обвалить всю систему из-за одного специфического подтипа, который то и нужен только для крайних случаев, и понимая, что воспользоваться контейнером, в котором окажется Null Object, можешь не только ты, а и твой коллега-разработчик, который тоже захочет воспользоваться стандартными алгоритмами - понимаешь что такой риск слишком велик.

Тем более, что присмотревшись к сущности паттерна Null Object - начинаешь понимать, что этот паттерн является ярким проявлением неполной инициализации, со всеми вытекающими из этого проблемами(можно бегло прочитать у Саттера в его Exceptional C++). И тогда уже просто радуешься тому, что не успел применить этот паттерн.

В результате получается, что в случаях, которые кажутся достойными применения Null Object, лучше применять Proxy с его lazy loading - сама реализация Proxy позволит подтянуть нужные данные в операциях сравнения, когда они понадобятся, и повторить попытку подтягивания, если оно сорвалось.

2 комментария:

  1. Здравствуйте. Null и NaN это все-таки разные понятия. Null == Null is true. NaN == NaN is false. В конце "Introduce Null Object" есть "Other Special Cases" где автор упоминает NaN в контексте Special Case паттерна, а не Null Object.

    ОтветитьУдалить
  2. Здравствуйте. Null и NaN это все-таки разные понятия. Null == Null is true. NaN == NaN is false. В конце "Introduce Null Object" есть "Other Special Cases" где автор упоминает NaN в контексте Special Case паттерна, а не Null Object.

    ОтветитьУдалить