Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Клуб программистов > Свободное общение
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 14.11.2012, 19:27   #1
the_deer_one
Участник клуба
 
Аватар для the_deer_one
 
Регистрация: 04.04.2010
Сообщений: 1,554
По умолчанию fluent builder 'ы

Часто стали попадаться такие вещи.

Код:
SimpleTrigger trigger = (ISimpleTrigger) TriggerBuilder.Create()
                                                       .WithIdentity("trigger1", "group1")
                                                       .StartAt(startTime)
                                                       .WithSimpleSchedule(x  => x.WithIntervalInSeconds(3).RepeatForever())
                                                       .Build();
И в нюните что то подобное появилось

Код:
Assert.That( new int[] { 1, 2, 2 }, Is.Not.EquivalentTo( iarray ) );
Оказывается у этого даже название есть.
https://nesteruk.wordpress.com/2010/...der-in-csharp/


А в чём фишка то?

Чем первый способ записи лучше чем:

Код:
var trigger = TriggerBuilder.Create();
trigger.SetIdentity("trigger1", "group1");
trigger.StartTime = startTime;
trigger.IntervalInSeconds = 3;
trigger.RepeatForever = true;
Или второй чем:
Код:
Asert.AreNotEqual(new int[] { 1, 2, 2 }, iarray)
the_deer_one вне форума Ответить с цитированием
Старый 14.11.2012, 19:46   #2
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,091
По умолчанию

Цитата:
Сообщение от the_deer_one Посмотреть сообщение
Чем первый способ записи лучше чем:

Код:
var trigger = TriggerBuilder.Create();
trigger.SetIdentity("trigger1", "group1");
trigger.StartTime = startTime;
trigger.IntervalInSeconds = 3;
trigger.RepeatForever = true;
Лучше тем, что он модный. Так же первый способ вносит усложнение в тестирование, увеличивает количество классов и прочие приятные бонусы появляются в скучном коде
Цитата:
Сообщение от the_deer_one Посмотреть сообщение
Код:
Asert.AreNotEqual(new int[] { 1, 2, 2 }, iarray)
Тут уже в случае с fluent builder код возможен более гибкий и меньше дублирований будет.
Для Assert нужно писать методы AreNotEqual, AreEqual, AreLess, AreNotLess, ... Тут уже использование подобного подхода вполне может быть оправдано.
Просто важно эту штуку правильно использовать, а не пихать всюду моды для.
pu4koff вне форума Ответить с цитированием
Старый 14.11.2012, 20:14   #3
m0nax
Форумчанин
 
Аватар для m0nax
 
Регистрация: 25.09.2009
Сообщений: 525
По умолчанию

Цитата:
Сообщение от the_deer_one Посмотреть сообщение
Чем первый способ записи лучше чем:

Код:
var trigger = TriggerBuilder.Create();
trigger.SetIdentity("trigger1", "group1");
trigger.StartTime = startTime;
trigger.IntervalInSeconds = 3;
trigger.RepeatForever = true;
так ведь дублирование кода
там всего 1 раз написано слово trigger, а тут аж целых 5
m0nax вне форума Ответить с цитированием
Старый 14.11.2012, 21:01   #4
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Pattern Builder - повышаем читаемость, скрываем доступ к полям класса, благодаря собственно билдеру.
DSL - повышаем читаемость и качество кода в общем, не злоупотреблять.

p.s. pu4koff - модно? Ну что же вы, помоему тут мода вообще не причем.
BOBAH13 вне форума Ответить с цитированием
Старый 14.11.2012, 22:40   #5
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,091
По умолчанию

Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
p.s. pu4koff - модно? Ну что же вы, помоему тут мода вообще не причем.
Что мешает создавать понятные классы и не выпячивать что не следует наружу как и положено модификаторами доступа (private, protected)?
Я не против такого подхода и это может быть удобно, но люди же эту штуку используют не потому что нужно, а потому что хочется.
Я не против "стандартного" StringBuilder'a и это очень полезная штука. Только вот он не работает по принципу: в методе Create создадим объект типа string, а в методе Append создадим взамен новую строку или тупо вызовем нужные методы класса string.
Человеки просто как бараны услышали про паттерны и теперь у всех синглтоны, фабрики, ... Раньше как-то жили и не парились, а теперь всё по науке, по шаблонам и мышление стало: так, вот тут я замучу вот этот паттернт, а тут... сейчас книжку полистаю, подберу подходящий... во. Вот этот паттерн тут забабахаю и крутотень будет.
Если посмотреть на TriggerBuilder из первого поста.
Я так полагаю, что последовательность выполнения WithIdentity, StartAt и WithSimpleSchedule не важна, главное - что они после Create и до Build. Только благодаря этой крутой штуке мы вместо прямого вызова конструктора для нужного типа вызываем какой-то метод ненужного нам класса. Потом вызываем методы в непонятной последовательности (будут они одинаково хорошо работать, если строки местами поменять?), а потом еще вызываем некий Build для выполнения всей этой радости.
Вопрос тестирования и отладки для меня выглядит сомнительным и усложнения неоправданы. До кучи мы получаем дополнительный класс и логика работы этого класса размазана уже по двум классам (Builder же должен знать что зачем и почему в этом классе происходит и в случае изменений у нас появляется дополнительная головная боль).
Моё мнение, что все эти Builder'ы должны хранить состояние в некоем своём виде и максимально отдаляться от типа создаваемого объекта. Объект нужного типа должен создаваться определенным методом, а у билдера должен быть свой конструктор, т.к. не всегда может быть некое "нулевое" состояние, т.е. должно быть как-то так:
Код:
MyBuilder b = new MyBuilder(init_param);
b.Select("1").From("2").Where(3).OrderBy(4);

for (int i = 0; i < 10; ++i)
{
  b.ToMy(); // Только тут создание объекта класса My, т.е. тут будет создано 10 разных объектов с одинаковым состоянием
}
Без всех этих штук это получается не то фабрика, не то декоратор какой, не то еще какая заумная хрень из паттернов.
Класс нужен для выполнения каких-то функций и если он получился убогим и неудобным, значит нужно не таких вот билдеров-помощников лепить, а делать нормальный класс. Не должно это быть просто обёрткой, а иначе получится 5 уровней обёрток, а внутри фигня.
pu4koff вне форума Ответить с цитированием
Старый 14.11.2012, 22:56   #6
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

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

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

Код:
val obj = new Object("first", "second", 3, Enum.FOURTH, CONSTANT_FIFTH);
и другой огромный список. Читабильности - ноль.

Или же другой вариант, класс помошник - билдер идет внутри класса Object и дает нам следующий вариант:

Код:
val obj = Object.Builder.withFirstAndSecond("first", "second").withThird(3).withFourth(Enum.FOURTH).withFifth(CONSTANT_FIFTH).build();
Получаем obj с геттерами но без сеттеров, сеттеры были установлены приватно и доступны классу Object.Builder, соотвественно все with методы для Object.Builder опциональны, и могут быть не вызваны вовсе, тогда все значения будут по умолчанию, в то время как статический метод withFirstAndSecond дает понять что эти First и Second должны быть установлены как required параметры.

UPD:
Код:
var trigger = TriggerBuilder.Create();
trigger.SetIdentity("trigger1", "group1");
trigger.StartTime = startTime;
trigger.IntervalInSeconds = 3;
trigger.RepeatForever = true;
Все поля открыты публично для изменения в любой момент жизни объекта, что может повлечь side-еффект для логики самого класса. Билдер даст возможность все или только нужные поля установить и дать готовый объект со скрытием сеттеров.

Последний раз редактировалось BOBAH13; 14.11.2012 в 23:00.
BOBAH13 вне форума Ответить с цитированием
Старый 14.11.2012, 23:33   #7
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,091
По умолчанию

Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Ну вы прямо бурно реагируете как то.
Нормально я реагирую. Просто очередная крутая штука, которую пихают куда надо и куда не надо
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Простой пример, сам с таким встречаюсь очень часто: нужно создать объект класса, много полей, все поля должны быть установлены, т.е. получаем дефолтные значения.
Если они все должны быть установлены, то этот удобный Builder нам не подскажет, что ничего не было забыто и получим ошибку в Runtime, когда она могла быть во время компиляции.
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Ну как вы пишете, билдер зло, но открывать сеттеры нельзя, значит все идет в конструктор. Получаем:

Код:
val obj = new Object("first", "second", 3, Enum.FOURTH, CONSTANT_FIFTH);
и другой огромный список. Читабильности - ноль.
Если уж так не нравятся длинные конструкторы, тогда добавляем:
Код:
struct MySuperStruct
{
  string first;
  string second;
  ...
}
...
MySuperStruct str = new MySuperStruct();
str.first = ...
...
val obj = new Object(str);
Помимо всего прочего, с большой долей вероятности разработчик забьёт на конструктор на самом деле нужного класса (вместо длинного конструктора с кучей параметров получится пустой). В итоге половина логики класса будет перетащена в Builder и поимеем макаронину в коде.
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Или же другой вариант, класс помошник - билдер идет внутри класса Object и дает нам следующий вариант:

Код:
val obj = Object.Builder.withFirstAndSecond("first", "second").withThird(3).withFourth(Enum.FOURTH).withFifth(CONSTANT_FIFTH).build();
Получаем obj с геттерами но без сеттеров, сеттеры были установлены приватно и доступны классу Object.Builder, соотвественно все with методы для Object.Builder опциональны, и могут быть не вызваны вовсе, тогда все значения будут по умолчанию, в то время как статический метод withFirstAndSecond дает понять что эти First и Second должны быть установлены как required параметры.
Не знаю, мне withFirstAndSecond ничего не даёт понять, я не понимаю чем это лучше выше предложенной мною структура. Подобная запись хорошо ложится на что-то вроде потоков, где важна последовательность действий. Тут же порядок указания значений параметрам не критичен. Вот вывалит этот вызов мне исключение, если withFirstAndSecond поменять местами с withFifth? Что в итоге происходит с классом Object? У него закрыт конструктор и он в жесткой связке с этим самым Builder? Или же можно вполне себе использовать его без заморочек с этой фичей и писать обычный конструктор и нормально туда параметры передавать?
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Все поля открыты публично для изменения в любой момент жизни объекта, что может повлечь side-еффект для логики самого класса. Билдер даст возможность все или только нужные поля установить и дать готовый объект со скрытием сеттеров.
По этой логике нужно делать все объекты константными и для всех классов писать билдеры. Как по мне, так билдер должен идти как дополнительная фича (без всяких специальных затачиваний нужного класса под это дело). Это чисто оптимизационная штука, которая позволяет быстрее создавать кучи однотипных объектов или же совершать ряд преобразований для тяжелых объектов или что там еще в голову придёт. Когда получается класс, который слишком сложен и для его использования нужно добавить еще один класс - это нездоровая вещь и с этим нужно бороться.
pu4koff вне форума Ответить с цитированием
Старый 15.11.2012, 01:18   #8
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Цитата:
если withFirstAndSecond поменять местами с withFifth
Вы не можете этого сделать, т.к. я пишу Object.Builder а не new Object.Builder(). Может я был не столь детален, но withFirstAndSecond статический метод, создает билдер и устанавливает required параметры, остальные with это опциональные значения, и вызов их в каком порядке не важен.

p.s. не люблю когда люди приводят кучу текста и комментариев абсолютно игнорируя мои аргументы несколько раз. Ознакомтесь со Scala к примеру, в ней много подобных конструкций, т.к. подобный код является самодокументрированным. Посмотрите на названия функий в Objective C, посмотрите на тендеции развития Android SDK от Google, тот же Animation. Конечно же это все, что я привожу
Цитата:
нездоровая вещь и с этим нужно бороться.

Последний раз редактировалось BOBAH13; 15.11.2012 в 01:23.
BOBAH13 вне форума Ответить с цитированием
Старый 15.11.2012, 08:03   #9
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,091
По умолчанию

Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Вы не можете этого сделать, т.к. я пишу Object.Builder а не new Object.Builder(). Может я был не столь детален, но withFirstAndSecond статический метод, создает билдер и устанавливает required параметры
Почему тогда это не конструктор, а непонятный статический метод?
Поясняю: В делфях конструкторы можно назвать как угодно и плюсовики (и прочие, где конструкторы совпадают с именем класса) на этот счет часто говорили, что это неудобно, неправильно, т.к. непонятно как там конструктор называется... Тут получается уже за фичу, что создание объекта производится методом с понятным автору названием (даже хуже получается, т.к. нет никакого специального ключевого слова и этот метод визуально ничем не отличается от других статических).
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
, остальные with это опциональные значения, и вызов их в каком порядке не важен.
Если уже после первого with был создан объект создаваемого класса, то на это можно только надеяться и верить, что потом это поведение никак не изменится.
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
p.s. не люблю когда люди приводят кучу текста и комментариев абсолютно игнорируя мои аргументы несколько раз.
И на какой аргумент я не ответил и на какой я не привёл свою альтернативу?
Чем в итоге предложенная мною обычная вспомогательная структура хуже и чем не подходит? Не считаю, что выстраивание методов в какой-то поток понятнее и лучше, чем старый добрый оператор присваивания.
Метод - это глагол, какое-то действие. Передача параметров в конструктор - это не действие.
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Ознакомтесь со Scala к примеру, в ней много подобных конструкций, т.к. подобный код является самодокументрированным. Посмотрите на названия функий в Objective C, посмотрите на тендеции развития Android SDK от Google, тот же Animation.
Может быть как-нибудь на досуге. Если есть у них что-то типа msdn в вебе, то не отказался бы от ссылки на ресурс, дабы примеры кода посмотреть.
Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Конечно же это все, что я привожу
Я писал, что в целом я не против этих всех билдеров, но я за их правильное использование. В целом тенденция идёт дурацкая. Каждой фигне придумывают названия и любители новых и не очень фич стремятся эти все штуки обязательно использовать. ООП еще не знает человек, классы нормально сделать не может, но уже у него там "фабрика" из книжки умной перепечатана, куча слоёв выделена и всё типа труъ, а потом происходит затык, который в книжке той естественно не описан и начинается макаронное веселье.
pu4koff вне форума Ответить с цитированием
Старый 15.11.2012, 19:10   #10
the_deer_one
Участник клуба
 
Аватар для the_deer_one
 
Регистрация: 04.04.2010
Сообщений: 1,554
По умолчанию

BOBAH13
Цитата:
p.s. не люблю когда люди приводят кучу текста и комментариев абсолютно игнорируя мои аргументы несколько раз.
И не мудрено. Твоя русская речь становится всё больше похожа на перевод промта. Я пять раз перечитал тебя пока понял.

pu4koff
Цитата:
Вот вывалит этот вызов мне исключение, если withFirstAndSecond поменять местами с withFifth?
Так эти методы разные классы билдеров - дебилдеров вызывают.
Скажем RequiredBilder и UnrequiredBilder.

С такой позиции вполне оправданная штукенция.
the_deer_one вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
CodeGear C++ Builder 2007 Lite не может откомпилировать исходники C++ Builder 6 Ecosasha C++ Builder 2 22.11.2013 15:02
c++ builder CepBep Помощь студентам 0 07.07.2012 17:19
переезд из C++ Builder 6 в C++ Builder 2009 NadS Помощь студентам 2 18.03.2012 06:44
Синтаксис Delphi Builder --> C++ Builder KingBelt C++ Builder 2 28.11.2010 16:25
Перенести код из C++ Builder 5 в C++ Builder 2009 Kreadlling C++ Builder 2 13.09.2009 14:00