null vs Null Object patter [из Diff между чистый ADO.NET v ..]

kokoc88

ужасно
простой вариант (достаточно подключить библиотеку из нескольких функций)
Почему рядом с Option не рассматриваются такие примитивные вещи, как null object? Его можно точно так же встроить в виде фреймворка и тогда можно вообще не переписывать самый первый пример кода. Этот подход описан как паттерн, и у Фаулера присутствует соответствующий рефакторинг.

Dasar

Почему рядом с Option не рассматриваются такие примитивные вещи, как null object?
во-первых, при использовании паттерна null object происходит перенос ответственности из клиентского кода во внутрь объекта, что требует преждевременного принятия решения о том, каким должно быть поведение произвольного клиентского кода при null-евом значении, а также сильно затрудняет возможность обеспечить, что разные правила для одного и того же объекта по разному обрабатывали null
во-вторых, использование паттерна null object значительно раздувает код. Число типов, как минимум умножается сразу на 3: каждый тип необходимо заменить на интерфейс, и под этот интерфейс сделать две реализации: нормальную и нулевую.

kokoc88

во-первых, при использовании паттерна null object происходит перенос ответственности из клиентского кода во внутрь объекта, что требует преждевременного принятия решения о том, каким должно быть поведение произвольного клиентского кода при null-евом значении, а также сильно затрудняет возможность обеспечить, что разные правила для одного и того же объекта по разному обрабатывали null
Это неправда. В твоём примере всегда достаточно последнего свойства. Кроме того, там нет разницы: код под Option и под null вообще одинаковый. Да и "логику произвольного клиентского кода" ты почему-то не хочешь перенести в объект, но спокойно перенёс в _nv.
во-вторых, использование паттерна null object значительно раздувает код. Число типов, как минимум умножается сразу на 3: каждый тип необходимо заменить на интерфейс, и под этот интерфейс сделать две реализации: нормальную и нулевую.
Это неправда. Каждый тип уже реализует интерфейс, которого почти всегда вполне достаточно.

Dasar

спокойно перенёс в _nv.
во-первых, в _nv нет никакой прикладной логики
во-вторых, вместо _n/_nv можно в каждом конкретном месте вызвать любую другую обработку null-я
Каждый тип уже реализует интерфейс, которого почти всегда вполне достаточно.
такое обычно бывает в java-way, который, имхо, приводит к большому кол-ву ненужного кода и monkey-кодированию.

kokoc88

во-первых, в _nv нет никакой прикладной логики
во-вторых, вместо _n/_nv можно в каждом конкретном месте вызвать любую другую обработку null-я
В null object тоже нет, и можно вызвать любую другую обработку интересующего нас null.
такое обычно бывает в java-way, который, имхо, приводит к большому кол-ву ненужного кода и monkey-кодированию.

Такое обычно в любом ООП языке, это же базовая теория: класс имеет один или более типов.

Dasar

В null object тоже нет, и можно вызвать любую другую обработку интересующего нас null.
для этого как минимум необходимо уметь отличать на уровне клиента Null Object от не Null Object, что уже нарушает чистоту паттерна Null Object.
например, какое ты решение предлагаешь через Null Object для следующих двух правил?

if (car._n(_=>_.бачок_омывателя)._n(_=>_.датчик_уровня)._nv(_=>_.уровень)
< рекомендуемые_параметры_эксплуатации._n(_ => _.уровень_бачка_омывателя)._nv(_=>_.min
{
приборная_панель._n(_=>_.лампочка_работы_омывателя)._n(_=>_.зажечь;
}
if (car != null && car.бачок_омывателя == null)
{
приборная_панель._n(_ => _.лампочка_оповещения_об_отсутствии_бачка_омывателя_в_машине)._n(_=>_.зажечь;
}


Такое обычно в любом ООП языке, это же базовая теория: класс имеет один или более типов.
чтобы это утверждение имело смысл, приведи, пожалуйста, какие определения понятий "класс" и "тип" ты используешь
У класса string сколько типов? Сколько классов у типа UInt32?

kokoc88

для этого как минимум необходимо уметь отличать на уровне клиента Null Object от не Null Object, что уже нарушает чистоту паттерна Null Object.
Даже если надо его отличать, в этом не будет ничего страшного. Я могу использовать null object и null, код получится короче и понятнее. Я могу предложить много вариантов более простого кода, который намного удобнее читать и поддерживать:

if (car.бачок_омывателя.датчик_уровня.уровень < рекомендуемые_параметры_эксплуатации.уровень_бачка_омывателя.min)
{
приборная_панель.лампочка_работы_омывателя.зажечь;
}

if (car.нет_бачка_омывателя)
{
приборная_панель.лампочка_оповещения_об_отсутствии_бачка_омывателя_в_машине.зажечь;
}

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

kokoc88

чтобы это утверждение имело смысл, приведи, пожалуйста, какие определения понятий "класс" и "тип" ты используешь
У класса string сколько типов? Сколько классов у типа UInt32?
Я не буду этого делать, потому что использую понятия из книжек; а ты, чтобы отмазаться от ошибок, обычно устраиваешь полемику, где требуешь определения вплоть до определения слова "определение".

Dasar

Я не буду этого делать, потому что использую понятия из книжек;
в следующей фразе, ты явно используешь понятия "класс", "тип" и "имеет" не из книжек.
Такое обычно в любом ООП языке, это же базовая теория: класс имеет один или более типов.
Класс — разновидность абстрактного типа данных в объектно-ориентированном программировании (ООП характеризуемый способом своего построения
Тип данных — фундаментальное понятие теории программирования. Тип данных определяет множество значений, набор операций, которые можно применять к таким значениям, и, возможно, способ реализации хранения значений и выполнения операций.

6yrop

еще ответь про вот это

z: {
Console.WriteLine("z=");
Console.Write(z);
}

Напиши свой аналог.

Dasar


if (z.IsSome)
{
Console.WriteLine("z=");
Console.Write(z);
}

kokoc88

в следующей фразе, ты явно используешь понятия "класс", "тип" и "имеет" не из книжек.
Видишь ли, я уверен, что использую понятия из книжек. Смысл моей фразы, если ты её не понял, был в том, что новый интерфейс для реализации паттерна null object вовсе необязателен. Для этого можно использовать интерфейс существующего класса.

Dasar

Смысл моей фразы, если ты её не понял, был в том, что новый интерфейс для реализации паттерна null object вовсе необязателен.
".нет_бачка_омывателя " - вот это же явно новый интерфейс. Причем для каждого объекта свой собственный

kokoc88

".нет_бачка_омывателя " - вот это же явно новый интерфейс. Причем для каждого объекта свой собственный
Нет, это просто интерфейс интересующего нас объекта. Как у каждого объекта, которые имеют один тип, он может быть своим собственным, я не представляю.

Dasar

Как у каждого объекта, которые имеют один тип, он может быть своим собственным, я не представляю.
речь о другом, что появляются дополнительные интерфейсы со свойствами: .нет_бачка_омывателя, .нет_датчика_уровня, .нет_лампочки_бачка_омывателя и т.д., и вместо универсального сравнения zzz != null необходимо в каждом случае использовать частное свойство.

kokoc88

речь о другом, что появляются дополнительные интерфейсы со свойствами: .нет_бачка_омывателя, .нет_датчика_уровня, .нет_лампочки_бачка_омывателя и т.д., и вместо универсального сравнения zzz != null необходимо в каждом случае использовать частное свойство.
Дополнительные интерфейсы не появляются. Твою задачу хоть с null, хоть с null object, хоть с maybe надо решать как-то так. В любом нормальном проекте твой пример потребовали бы отрефакторить.
На самом деле очень сложно привести реальный жизненный пример на C#, когда гавнокод с maybe лучше, чем понятный и простой императивный стиль. Обычно ярые фонаты идут по двум путям: либо превращают весь проект в гавно, либо избирательно используют maybe, что опять же ведёт к разношёстному стилю и в итоге результат получается ещё более плачевным, чем в первом случае.

6yrop

2: Наше обсуждение принесло пользу. Спасибо. Делать это глобально, т.е. автоматический overloading на уровне компилятора, я считаю не правильно. Однако, для метода Param такой overloading имеет смысл:

public static Param<T> Param<T>(this T it)
{
...
}

public static Option<Param<T>> Param<T>(this Option<T> it)
{
return it.Select(_ => _.Param;
}

Тогда вот это выражение:

firstName.Nothing(string.IsNullOrEmpty).Select(_ => _.Param

заменится на:

firstName.Nothing(string.IsNullOrEmpty).Param

Dasar

В любом нормальном проекте твой пример потребовали бы отрефакторить.
во-первых, на практике это сделать невозможно, потому что за код дерева объектов и за код по его обработки отвечают две разные команды. Код объектов пишется разработчиками framework-а, а код по их обработке пишется инжиниринговой компанией - которая этот framework допиливает под нужды заказчика. Соответственно, первый не знают какое поведение хотят вторые во время отсутствия объекта.
во-вторых, все известные мне framework-и по обработке данных с высокой вариабельностью: gui, web, обработка документов со сложной структурой, обработка ast-а, работа с БД и т.д. не используют null pattern object,

kokoc88

во-первых, на практике это сделать невозможно, потому что за код дерева объектов и за код по его обработки отвечают две разные команды. Код объектов пишется разработчиками framework-а, а код по их обработке пишется инжиниринговой компанией - которая этот framework допиливает под нужды заказчика. Соответственно, первый не знают какое поведение хотят вторые во время отсутствия объекта.
При чём тут это и твой конкретный пример, который подлежит рефакторингу даже без проверок на null? Я точно так же могу написать, что команда "дерева объектов" не использовала maybe и добавить его туда мы никак не можем. Что интересно, в последнем случае мы как раз сможем использовать null object.
во-вторых, все известные мне framework-и по обработке данных с высокой вариабельностью: gui, web, обработка документов со сложной структурой, обработка ast-а, работа с БД и т.д. не используют null pattern object,
А все известные мне framework-и не используют maybe, и что?

Dasar

Я точно так же могу написать, что команда "дерева объектов" не использовала maybe и добавить его туда мы никак не можем.
неверное сравнение. Maybe не зависит от кода framework-ов, и соответственно его можно добавить в проект и без доброй воли разработчиков framework. Null object pattern целиком зависит от внутренностей framework и его не добавить без доброй воли разработчиков framework-а.
А все известные мне framework-и не используют maybe, и что?
так о том и речь, что для того, чтобы работать со всеми известными framework-ами и не городить вереницу проверок на null, удобнее использовать в том или ином виде maybe.

kokoc88

неверное сравнение. Maybe не зависит от кода framework-ов, и соответственно его можно добавить в проект и без доброй воли разработчиков framework. Null object pattern целиком зависит от внутренностей framework и его не добавить без доброй воли разработчиков framework-а.
Пока что всё как раз наоборот, поясняй детально, что ты собираешься делать. А то я чувствую, что сейчас от maybe ты перейдёшь к какому-то изврату...
так о том и речь, что для того, чтобы работать со всеми известными framework-ами и не городить вереницу проверок на null, удобнее использовать в том или ином виде maybe.
Об этом речи пока что нет: по-первых, все известные мне фреймворки не имеют проблем с доступом к объектам через десятки геттеров; во-вторых, они же не имеют никаких проблем с null.
Оставить комментарий
Имя или ник:
Комментарий: