Объединение методов - это практика, когда методы объекта возвращают сам объект для вызова результата для другого метода. Как это:
participant.addSchedule(events[1]).addSchedule(events[2]).setStatus('attending').save()
Кажется, это считается хорошей практикой, так как он создает читаемый код или «свободный интерфейс». Однако, мне кажется, что вместо этого кажется, что он нарушает нотацию вызова объекта, подразумеваемую самой ориентацией объекта - результирующий код не представляет выполнение действий с результатом предыдущего метода, как обычно ожидается, что объектно-ориентированный код будет работать:
participant.getSchedule('monday').saveTo('monnday.file')
Это различие позволяет создать два разных значения для точечной нотации «вызова результирующего объекта»: в контексте объединения в цепочку приведенный выше пример читается как сохранение объекта участника , даже если этот пример фактически предназначен для сохранения расписания. объект, полученный getSchedule.
Я понимаю, что разница здесь в том, должен ли вызываемый метод возвращать что-то или нет (в этом случае он будет возвращать сам вызываемый объект для создания цепочки). Но эти два случая не отличаются от самой нотации, только от семантики вызываемых методов. Когда цепочка методов не используется, я всегда могу знать, что вызов метода воздействует на что-то, связанное с результатом предыдущего вызова - с цепочкой это предположение нарушается, и мне приходится семантически обрабатывать всю цепочку, чтобы понять, что на самом деле представляет собой объект называется действительно так. Например:
participant.attend(event).setNotifications('silent').getSocialStream('twitter').postStatus('Joining '+event.name).follow(event.getSocialId('twitter'))
Там последние два вызова метода относятся к результату getSocialStream, тогда как предыдущие вызовы относятся к участнику. Может быть, это плохая практика - писать цепочки с изменяющимся контекстом (не так ли?), Но даже тогда вам придется постоянно проверять, действительно ли точечные цепочки, которые выглядят одинаково, соответствуют одному и тому же контексту или работают только с результатом. ,
Мне кажется, что, хотя поверхностное сцепление методов действительно производит читабельный код, перегрузка значения точечной нотации только приводит к еще большей путанице. Поскольку я не считаю себя гуру программирования, я предполагаю, что вина моя. Итак: что мне не хватает? Я понимаю метод цепочки как-то неправильно? Есть ли случаи, когда цепочка методов особенно хороша, или где особенно плохо?
Sidenote: Я понимаю, что этот вопрос можно рассматривать как высказывание мнения, замаскированное под вопрос. Однако это не так - я искренне хочу понять, почему создание цепочек считается хорошей практикой, и где я ошибаюсь, думая, что это нарушает присущую объектно-ориентированную нотацию.
источник
.
, которая игнорирует любые возвращаемые значения метода и всегда вызывает любые цепочечные методы, использующие один и тот же объект.Ответы:
Я согласен, что это субъективно. По большей части я избегаю цепочки методов, но недавно я также обнаружил случай, когда это было правильно - у меня был метод, который принимал около 10 параметров и требовал большего, но в большинстве случаев вам нужно было только указать несколько. С переопределениями это стало очень громоздким и очень быстрым. Вместо этого я выбрал подход цепочки:
Подход цепочки методов был необязательным, но он облегчал написание кода (особенно с IntelliSense). Имейте в виду, что это один изолированный случай, и он не является общей практикой в моем коде.
Дело в том, что в 99% случаев вы, вероятно, можете делать то же самое или даже лучше без цепочки методов. Но есть 1%, где это лучший подход.
источник
P = MyObject.GetParamsObj().SomeParameter(asdasd).SomeOtherParameter(asdasd); Obj = MyObject.Start(); MyObject.Execute(P);
. У вас есть преимущество в возможности повторного использования этого объекта параметра в других вызовах, что является плюсом!PizzaBuilder.AddSauce().AddDough().AddTopping()
больше ссылок здесьlist.add(someItem)
, я читаю это как «этот код добавляетsomeItem
кlist
объекту». поэтому, когда я читаюPizzaBuilder.AddSauce()
, я читаю это естественно как «этот код добавляет соус кPizzaBuilder
объекту». Другими словами, я вижу оркестратор (который выполняет добавление) как метод, в который встроен кодlist.add(someItem)
илиPizzaBuilder.addSauce()
. Но я просто думаю, что пример PizzaBuilder немного искусственный. Ваш примерMyObject.SpecifySomeParameter(asdasd)
хорошо работает для меня.Просто мои 2 цента;
Сцепление методов усложняет отладку: - Вы не можете поместить точку останова в сжатую точку, поэтому вы можете приостановить программу именно там, где вы хотите - Если один из этих методов выдает исключение, и вы получаете номер строки, вы понятия не имеете какой метод в «цепочке» вызвал проблему.
Я думаю, что это хорошая практика - всегда писать очень короткие и лаконичные строки. Каждая строка должна просто сделать один вызов метода. Предпочитаю больше строк длинным линиям.
РЕДАКТИРОВАТЬ: комментарий упоминает, что методы цепочки и переносы строк являются отдельными. Это правда. Однако в зависимости от отладчика может быть или не быть возможности поместить точку останова в середине оператора. Даже если вы можете, использование отдельных строк с промежуточными переменными дает вам гораздо больше гибкости и целую кучу значений, которые вы можете просмотреть в окне Watch, что помогает процессу отладки.
источник
Лично я предпочитаю методы цепочки, которые действуют только на исходный объект, например, устанавливают несколько свойств или вызывают методы служебного типа.
Я не использую его, когда в моем примере один или несколько связанных методов возвращают любой объект, кроме foo. Хотя синтаксически вы можете связать что угодно, если вы используете правильный API для этого объекта в цепочке, изменение объектов IMHO делает вещи менее читабельными и может привести к путанице, если API для разных объектов имеют какие-либо сходства. Если вы делаете некоторые действительно общий вызов метода в конце (
.toString()
,.print()
, что угодно) , какой объект вы в конечном счете действует на? Кто-то, случайно читающий код, может не заметить, что это будет неявно возвращаемый объект в цепочке, а не исходная ссылка.Цепочка различных объектов также может привести к неожиданным ошибкам. В моих примерах, предполагая, что foo является действительным, все вызовы метода являются «безопасными» (например, действительными для foo). В примере ОП:
... как сторонний разработчик, смотрящий на код, нет гарантии, что getSchedule на самом деле вернет действительный, ненулевой объект расписания. Кроме того, отладка этого стиля кода часто намного сложнее, так как многие IDE не будут оценивать вызов метода во время отладки как объект, который вы можете проверить. IMO, всякий раз, когда вам может понадобиться объект для проверки в целях отладки, я предпочитаю иметь его в явной переменной.
источник
Participant
не является допустимым ,Schedule
тоgetSchedule
метод предназначен для возвратаMaybe(of Schedule)
типа иsaveTo
метод предназначен для приемаMaybe
типа.У Мартина Фаулера есть хорошее обсуждение здесь:
источник
На мой взгляд, метод цепочки - это новинка. Конечно, это выглядит круто, но я не вижу в этом никаких реальных преимуществ.
Как:
лучше чем:
Исключением может быть ситуация, когда addObject () возвращает новый объект, и в этом случае код без цепочки может быть немного более громоздким, например:
источник
Это опасно, потому что вы можете зависеть от большего количества объектов, чем ожидалось, как, например, ваш вызов возвращает экземпляр другого класса:
Я приведу пример:
foodStore - это объект, который состоит из множества ваших продуктовых магазинов. foodstore.getLocalStore () возвращает объект, который содержит информацию о ближайшем хранилище к параметру. getPriceforProduct (что угодно) - это метод этого объекта.
Поэтому, когда вы вызываете foodStore.getLocalStore (параметры) .getPriceforProduct (что угодно)
Вы зависите не только от FoodStore, но и от LocalStore.
Если getPriceforProduct (что-либо) когда-либо изменится, вам нужно изменить не только FoodStore, но и класс, который вызвал цепочечный метод.
Вы всегда должны стремиться к слабой связи между классами.
Это, как говорится, мне лично нравится цеплять их при программировании Ruby.
источник
Многие используют цепочку методов для удобства, а не для удобства чтения. Цепочка методов приемлема, если она включает в себя выполнение одного и того же действия с одним и тем же объектом - но только в том случае, если это действительно повышает удобочитаемость, а не только для написания меньшего количества кода.
К сожалению, многие используют метод цепочки в соответствии с примерами, приведенными в вопросе. Хотя их все еще можно сделать читаемыми, они, к сожалению, вызывают высокую связь между несколькими классами, поэтому это нежелательно.
источник
Это кажется субъективным.
Метод цепочки не является чем-то плохим или хорошим по своей сути.
Читаемость это самая важная вещь.
(Также учтите, что большое количество методов в цепочке сделает вещи очень хрупкими, если что-то изменится)
источник
Преимущества цепочки
т. , где мне нравится ее использовать
Одним из преимуществ цепочки, о котором я не упомянул, была возможность использовать его во время инициализации переменной или при передаче нового объекта в метод, не будучи уверенным, является ли это плохой практикой или нет.
Я знаю, что это надуманный пример, но скажем, у вас есть следующие классы
И скажем, у вас нет доступа к базовому классу, или Скажите, что значения по умолчанию являются динамическими, основанными на времени и т. Д. Да, вы можете создать экземпляр, затем изменить значения, но это может стать громоздким, особенно если вы просто передаете значения для метода:
Но не намного ли это легче читать:
Или как насчет ученика?
против
Вот как я использовал цепочку, и обычно мои методы предназначены только для конфигурации, поэтому они имеют длину всего 2 строки, затем установите значение
Return Me
. Для нас это вычистило огромные строки, которые очень трудно читать и понимать, в одну строку, которая читается как предложение. что-то вродеЧто-то вроде
Ущерб Цепи
т.е. где я не люблю его использовать
Я не использую цепочку, когда есть много параметров для передачи в подпрограммы, главным образом потому, что строки становятся очень длинными, и, как упоминалось в OP, это может сбить с толку, когда вы вызываете подпрограммы для других классов для передачи одному из методы сцепления.
Также существует опасение, что подпрограмма вернет недопустимые данные, поэтому до сих пор я использовал цепочку, только когда возвращаю тот же вызываемый экземпляр. Как указывалось, если вы создаете цепочку между классами, вы усложняете отладку (которая вернула ноль?) И можете увеличить связь между классами.
Вывод
Как и все в жизни и программировании, создание цепочек не является ни хорошим, ни плохим, если вы можете избежать плохого, то создание цепочек может принести большую пользу.
Я стараюсь следовать этим правилам.
источник
Объединение методов может позволить непосредственно создавать расширенные DSL в Java. По сути, вы можете смоделировать по крайней мере следующие типы правил DSL:
Эти правила могут быть реализованы с использованием этих интерфейсов
С помощью этих простых правил вы можете реализовать сложные DSL, такие как SQL, непосредственно в Java, как это делает jOOQ , библиотека, которую я создал. Смотрите довольно сложный пример SQL, взятый из моего блога здесь:
Другим хорошим примером является jRTF , небольшой DSL, разработанный для создания RTF-документов непосредственно в Java. Пример:
источник
В большинстве случаев цепочка методов может быть новинкой, но я думаю, что она имеет место. Один пример может быть найден в использовании Active Record CodeIgniter :
Это выглядит намного чище (и, на мой взгляд, более разумно), чем:
Это действительно субъективно; Каждый человек имеет свое собственное мнение.
источник
Я думаю, что основная ошибка - думать, что это вообще объектно-ориентированный подход, хотя на самом деле это скорее подход функционального программирования, чем что-либо еще.
Основные причины, по которым я его использую, - это удобочитаемость и предотвращение переполнения моего кода переменными.
Я не очень понимаю, о чем говорят другие, когда говорят, что это ухудшает читабельность. Это одна из наиболее сжатых и связных форм программирования, которые я когда-либо использовал.
Также это:
. ConvertTextToVoice.LoadText ( "source.txt") ConvertToVoice ( "destination.wav");
Вот как я бы обычно использовал это. Я использую это, чтобы связать число параметров по x, как я обычно не использую. Если бы я хотел ввести х число параметров в вызове метода, я бы использовал синтаксис params :
public void foo (params object [] items)
И приведите объекты на основе типа или просто используйте массив или коллекцию типов данных в зависимости от вашего варианта использования.
источник
Я согласен, я изменил способ, которым свободный интерфейс был реализован в моей библиотеке.
Перед:
После:
В реализации «before» функции модифицировали объект и заканчивались на
return this
. Я изменил реализацию на вернуть новый объект того же типа .Мои аргументы в пользу этого изменения :
Возвращаемое значение не имело ничего общего с функцией, оно было просто для поддержки цепочки, согласно OOP это должна была быть функция void.
Цепочка методов в системных библиотеках также реализует это (например, linq или string):
Исходный объект остается неизменным, что позволяет пользователю API решать, что с ним делать. Это позволяет:
Реализация копирования также может быть использована для строительства объектов:
Где
setBackground(color)
функция изменяет экземпляр и ничего не возвращает (как предполагалось) .Поведение функций более предсказуемо (см. Пункты 1 и 2).
Использование короткого имени переменной также может уменьшить помехи в коде, не применяя API в модели.
Вывод: по
моему мнению, свободный интерфейс, который использует
return this
реализацию, просто неверен.источник
return this
управлять или иначе. По моему мнению, он получает свободный API "неестественным" способом. (Добавлена причина 6: показать не беглую альтернативу, которая не имеет служебных / дополнительных функций)Абсолютно упущенный момент здесь заключается в том, что объединение методов позволяет использовать DRY . Это эффективная замена для «с» (который плохо реализован в некоторых языках).
Это имеет значение по той же причине, что DRY всегда имеет значение; если A оказывается ошибкой, и эти операции необходимо выполнить на B, вам нужно обновить только в 1 месте, а не в 3.
С практической точки зрения преимущество в этом случае невелико. Тем не менее, немного меньше печатать, немного более устойчивый (сухой), я возьму его.
источник
Я вообще ненавижу цепочку методов, потому что я думаю, что это ухудшает читабельность. Компактность часто путают с удобочитаемостью, но они не совпадают. Если вы делаете все в одном утверждении, то это компактно, но в большинстве случаев оно менее читаемо (труднее следовать), чем в нескольких утверждениях. Как вы заметили, если вы не можете гарантировать, что возвращаемое значение используемых методов одинаково, то объединение методов будет источником путаницы.
1.)
против
2.)
против
3.)
против
Как видите, вы почти ничего не выигрываете, потому что вам нужно добавить разрывы строк к вашему единственному выражению, чтобы сделать его более читабельным, и добавить отступ, чтобы было ясно, что вы говорите о разных объектах. Ну, если бы я хотел использовать язык на основе идентификаторов, то вместо этого я бы изучал Python, не говоря уже о том, что большинство IDE удаляют отступы путем автоматического форматирования кода.
Я думаю, что единственное место, где этот вид цепочки может быть полезен, - это передача потоков в CLI или объединение нескольких запросов в SQL. Оба имеют цену за несколько заявлений. Но если вы хотите решить сложные проблемы, вы в конечном итоге окажетесь даже у тех, кто платит цену и пишет код в нескольких выражениях с использованием переменных или написания скриптов bash и хранимых процедур или представлений.
Что касается СУХОЙ интерпретации: «Избегайте повторения знаний (не повторения текста)». и «Напечатывай меньше, даже не повторяй тексты», первое, что на самом деле означает этот принцип, но второе - это общее недоразумение, потому что многие люди не могут понять слишком сложную чушь, как «Каждый кусочек знания должен иметь один, однозначный, авторитетное представление в системе ". Второй - это компактность любой ценой, что нарушает этот сценарий, поскольку ухудшает читаемость. Первая интерпретация нарушается DDD, когда вы копируете код между ограниченными контекстами, потому что слабая связь более важна в этом сценарии.
источник
Хорошо:
Плохо:
Общее:
Хороший подход состоит в том, чтобы вообще не использовать цепочку, пока не возникнут ситуации или не подойдут конкретные модули.
В некоторых случаях сцепление может сильно ухудшить читабельность, особенно при взвешивании в точках 1 и 2.
Применительно к этому может быть использовано не по назначению, например, вместо другого подхода (например, передача массива) или смешивания методов причудливыми способами (parent.setSomething (). GetChild (). SetSomething (). GetParent (). GetSomething ()).
источник
Мнение Ответ
Самый большой недостаток цепочки заключается в том, что читателю может быть трудно понять, как каждый метод влияет на исходный объект, если он это делает, и какой тип возвращает каждый метод.
Некоторые вопросы:
Отладка, в большинстве языков, действительно может быть сложнее с цепочкой. Даже если каждый шаг в цепочке находится на своей собственной линии (что отрицательно сказывается на цели цепочки), может быть сложно проверить значение, возвращаемое после каждого шага, особенно для методов без мутаций.
Время компиляции может быть медленнее в зависимости от языка и компилятора, поскольку выражения могут быть гораздо более сложными для разрешения.
Я считаю, что, как и во всем, цепочка является хорошим решением, которое может пригодиться в некоторых ситуациях. Его следует использовать с осторожностью, понимая последствия и ограничивая количество элементов цепи несколькими.
источник
В типизированных языках (которые отсутствуют
auto
или эквивалентны) это избавляет разработчика от необходимости объявлять типы промежуточных результатов.Для более длинных цепочек вы можете иметь дело с несколькими различными промежуточными типами, вам нужно объявить каждый из них.
Я считаю, что этот подход действительно разработан в Java, где а) все вызовы функций являются вызовами функций-членов и б) требуются явные типы. Конечно, здесь есть компромисс в терминах, теряющий некоторую ясность, но в некоторых ситуациях некоторые люди находят это стоящим.
источник