Реализация цепочки на bean-компонентах очень удобна: нет необходимости перегружать конструкторы, мега-конструкторы, фабрики и обеспечивает повышенную читаемость. Я не могу думать о минусах, если только вы не хотите, чтобы ваш объект был неизменным , и в этом случае у него все равно не было бы сеттеров. Так есть ли причина, по которой это не соглашение об ООП?
public class DTO {
private String foo;
private String bar;
public String getFoo() {
return foo;
}
public String getBar() {
return bar;
}
public DTO setFoo(String foo) {
this.foo = foo;
return this;
}
public DTO setBar(String bar) {
this.bar = bar;
return this;
}
}
//...//
DTO dto = new DTO().setFoo("foo").setBar("bar");
myCustomDTO = DTOBuilder.defaultDTO().withFoo("foo").withBar("bar").Build();
Я бы сделал это, чтобы не противоречить общей идее, что сеттеры - это пустоты.new Foo().setBar('bar').setBaz('baz')
чувствует себя очень "свободно". Я имею в виду, конечно, что это может быть реализовано точно так же, но я бы очень рассчитывал прочитать что-то более похожееFoo().barsThe('bar').withThe('baz').andQuuxes('the quux')
Ответы:
Моя лучшая догадка: потому что это нарушает CQS
У вас есть команда (изменяющая состояние объекта) и запрос (возвращающий копию состояния - в данном случае сам объект), смешанные в одном методе. Это не обязательно проблема, но она нарушает некоторые основные принципы.
Например, в C ++ std :: stack :: pop () - это команда, которая возвращает void, а std :: stack :: top () - это запрос, который возвращает ссылку на верхний элемент в стеке. Классически, вы хотели бы объединить два, но вы не можете сделать это и быть в безопасности исключений. (Не проблема в Java, потому что оператор присваивания в Java не генерирует).
Если бы DTO был типом значения, вы могли бы достичь аналогичного конца с
Кроме того, цепочка возвращаемых значений - колоссальная боль, когда вы имеете дело с наследованием. Смотрите "Любопытно повторяющийся шаблон"
Наконец, есть проблема в том, что конструктор по умолчанию должен оставить вас с объектом, который находится в допустимом состоянии. Если вам нужно выполнить несколько команд, чтобы восстановить объект в правильное состояние, что-то пошло не так.
источник
abstract
T getSelf()
метод с возвращаемым универсальным типом. Теперь, вместо того чтобы возвращатьсяthis
из ваших сеттеров, вы,return getSelf()
а затем и любой переопределяющий класс просто делает тип универсальным сам по себе и возвращаетсяthis
изgetSelf
. Таким образом, сеттеры возвращают фактический тип, а не объявленный тип.Сохранение нескольких нажатий клавиш не является обязательным. Это может быть хорошо, но соглашения ООП больше заботятся о концепциях и структурах, а не о нажатиях клавиш.
Возвращаемое значение не имеет смысла.
Даже более чем бессмысленно, возвращаемое значение вводит в заблуждение, поскольку пользователи могут ожидать, что возвращаемое значение будет иметь смысл. Они могут ожидать, что это «неизменный сеттер»
На самом деле ваш сеттер мутирует объект.
Это не работает с наследованием.
я могу написать
но нет
Для меня, № 1 до № 3 являются важными. Хорошо написанный код не о приятном расположении текста. Хорошо написанный код о фундаментальных понятиях, отношениях и структуре. Текст - это только внешнее отражение истинного значения кода.
источник
public class Foo<T extends Foo> {...}
с возвращением сеттераFoo<T>
. Кроме того, эти методы «setter», я предпочитаю вызывать их «with» методами. Если перегрузка работает нормально, то простоFoo<T> with(Bar b) {...}
, иначеFoo<T> withBar(Bar b)
.Я не думаю, что это соглашение ООП, оно больше связано с дизайном языка и его соглашениями.
Кажется, вам нравится использовать Java. Java имеет спецификацию JavaBeans, которая определяет тип возвращаемого значения для установщика, который должен быть недействительным, то есть он находится в конфликте с цепочкой установки. Эта спецификация широко принята и реализована в различных инструментах.
Конечно, вы можете спросить, почему это не является частью спецификации. Я не знаю ответа, возможно, этот шаблон просто не был известен / популярен в то время.
источник
Object
, может привести кVoid
возвращению синглтона типа , если метод указывает вvoid
качестве своего возвращаемого типа. В других новостях, по всей видимости, «оставление комментария, но не голосование» является основанием для провала аудита «первой публикации», даже если это хороший комментарий. Я обвиняю шога в этом.Как говорили другие люди, это часто называют свободным интерфейсом .
Обычно сеттеры - это передача вызовов в переменных в ответ на логический код в приложении; ваш класс DTO является примером этого. Обычный код, когда сеттеры ничего не возвращают, является нормальным для этого. Другие ответы объяснили путь.
Однако есть несколько случаев, когда свободный интерфейс может быть хорошим решением, у них есть общее.
Настройка конфигурации, например, fluent-nhibernate
Настройка тестовых данных в модульных тестах с использованием специальных TestDataBulderClasses (Object Mothers)
Однако создать хороший свободный интерфейс очень сложно , поэтому оно того стоит, когда у вас много «статических» настроек. Также свободный интерфейс не должен смешиваться с «нормальными» классами; следовательно, шаблон строителя часто используется.
источник
Я думаю, что большая часть причин, по которым не принято заключать цепочки одного установщика за другим, заключается в том, что для этих случаев более типично видеть объект параметров или параметры в конструкторе. C # также имеет синтаксис инициализатора.
Вместо:
Можно написать:
(в JS)
(в C #)
(на Java)
setFoo
иsetBar
тогда больше не нужны для инициализации и могут быть использованы для мутации позже.Несмотря на то, что в некоторых случаях цепочка полезна, важно не пытаться помещать все в одну строку только ради сокращения символов новой строки.
Например
затрудняет чтение и понимание происходящего. Переформатирование в:
Гораздо проще понять и делает «ошибку» в первом варианте более очевидной. После того, как вы реорганизовали код в этот формат, у вас не будет никаких преимуществ перед:
источник
/
to представляет разрыв строки]With Foo(1234) / .x = 23 / .y = 47
будет эквивалентноDim temp=Foo(1234) / temp.x = 23 / temp.y = 47
. Такой синтаксис не создает двусмысленности, так.x
как сам по себе не может иметь никакого значения, кроме как связываться с непосредственно окружающим оператором «С» [если его нет, или у объекта нет членаx
, то не.x
имеет смысла]. Oracle не включил ничего подобного в Java, но такая конструкция легко вписалась бы в язык.Эта техника фактически используется в паттерне Builder.
Однако в целом этого избегают, потому что это неоднозначно. Неясно, является ли возвращаемое значение объектом (так что вы можете вызывать другие установщики), или же возвращаемым объектом является только что назначенное значение (также общий шаблон). Соответственно, принцип наименьшего удивления предполагает, что вы не должны пытаться предположить, что пользователь хочет видеть одно или другое решение, если оно не является фундаментальным для дизайна объекта.
источник
Obj* x = doSomethingToObjAndReturnIt(new Obj(1, 2, 3));
то, что я думаю, что оно также приобрело популярность, потому что оно отражаетa = b = c = d
, хотя я не уверен, что популярность была обоснованной. Я видел упомянутое вами возвращение предыдущего значения в некоторых элементарных библиотеках операций. Мораль истории? Это даже более запутанно, чем я это озвучил =)new BetterText(string).indent(4).box().print();
. В этом случае я обошел кучу гоблидов и взял строку, отступил, поместил ее в коробку и вывел ее. Возможно, вы даже захотите метод дублирования внутри каскада (например, скажем,.copy()
), чтобы все последующие действия больше не изменяли оригинал.Это больше комментарий, чем ответ, но я не могу комментировать, так что ...
Я просто хотел упомянуть, что этот вопрос удивил меня, потому что я не вижу в этом ничего необычного . На самом деле, в моей среде работы (веб-разработчик) очень и очень часто.
Например, вот как доктрина Symfony: генерирует: entity команда автоматически генерирует все
setters
, по умолчанию .JQuery объединяет большинство своих методов очень похожим образом.
источник
JAB
. В студенческие годы я привык смотреть на JS как на ненормальный язык сценариев, но я, работая пару лет с ним и выучив ПРАВИЛЬНЫЙ способ его использования, пришел к ... на самом деле, полюбил его , И я думаю, что с ES6 он станет действительно зрелым языком. Но что заставляет меня повернуть голову, так это то, что мой ответ имеет отношение к JS? ^^ U