Метод цепочки - почему это хорошая практика или нет?
Цепочка методов - это практика, когда методы объекта возвращают сам объект для вызова результата для другого метода. Как это:
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: Я понимаю, что этот вопрос можно рассматривать как высказывание мнения, замаскированное под вопрос. Однако это не так - я искренне хочу понять, почему создание цепочек считается хорошей практикой, и где я ошибаюсь, думая, что это нарушает присущую объектно-ориентированную нотацию.
20 ответов
Я согласен, что это субъективно. По большей части я избегаю цепочки методов, но недавно я также нашел случай, когда это было просто правильно - у меня был метод, который принимал около 10 параметров и требовал большего, но в большинстве случаев вам нужно было только указать мало. С переопределениями это стало очень громоздким и очень быстрым. Вместо этого я выбрал подход цепочки:
MyObject.Start()
.SpecifySomeParameter(asdasd)
.SpecifySomeOtherParameter(asdasd)
.Execute();
Это что-то вроде заводского образца. Подход цепочки методов был необязательным, но он облегчал написание кода (особенно с IntelliSense). Имейте в виду, что это один изолированный случай, и он не является общей практикой в моем коде.
Дело в том, что в 99% случаев вы, вероятно, можете делать то же самое или даже лучше без цепочки методов. Но есть 1%, где это лучший подход.
Просто мои 2 цента;
Сцепление методов усложняет отладку: - Вы не можете поставить точку останова в сжатой точке, поэтому вы можете приостановить программу именно там, где вы хотите - Если один из этих методов выдает исключение, и вы получаете номер строки, вы понятия не имеете какой метод в "цепочке" вызвал проблему.
Я думаю, что это хорошая практика - всегда писать очень короткие и краткие строки. Каждая строка должна просто сделать один вызов метода. Предпочитаю больше строк длинным линиям.
РЕДАКТИРОВАТЬ: комментарий упоминает, что метод цепочки и разрыва строки являются отдельными. Это правда. Однако в зависимости от отладчика может быть или не быть возможности разместить точку останова в середине оператора. Даже если вы можете, использование отдельных строк с промежуточными переменными дает вам гораздо большую гибкость и целый ряд значений, которые вы можете просмотреть в окне Watch, что помогает процессу отладки.
Лично я предпочитаю методы цепочки, которые действуют только на исходный объект, например, устанавливают несколько свойств или вызывают методы служебного типа.
foo.setHeight(100).setWidth(50).setColor('#ffffff');
foo.moveTo(100,100).highlight();
Я не использую его, когда один или несколько связанных методов вернут в моем примере любой объект, кроме foo. Несмотря на то, что синтаксически вы можете связывать что угодно, пока вы используете правильный API для этого объекта в цепочке, изменение объектов IMHO делает вещи менее читабельными и может привести к путанице, если API для разных объектов имеют какие-либо сходства. Если вы делаете какой-то действительно общий вызов метода в конце (.toString()
, .print()
что бы) на какой объект вы в конечном итоге воздействуете? Кто-то, случайно читающий код, может не заметить, что это будет неявно возвращаемый объект в цепочке, а не исходная ссылка.
Связывание различных объектов также может привести к неожиданным ошибкам. В моих примерах, предполагая, что foo допустим, все вызовы методов являются "безопасными" (например, действительными для foo). В примере ОП:
participant.getSchedule('monday').saveTo('monnday.file')
... нет гарантии (как сторонний разработчик смотрит на код), что getSchedule на самом деле вернет действительный, ненулевой объект расписания. Кроме того, отладка этого стиля кода часто намного сложнее, так как многие IDE не будут оценивать вызов метода во время отладки как объект, который вы можете проверить. IMO, всякий раз, когда вам может понадобиться объект для проверки в целях отладки, я предпочитаю иметь его в явной переменной.
У Мартина Фаулера есть хорошее обсуждение здесь:
Когда его использовать
Цепочка методов может значительно улучшить читаемость внутреннего DSL и, в результате, в некоторых умах стала почти синонимом для внутренних DSL. Тем не менее, метод Chaining лучше всего использовать в сочетании с другими комбинациями функций.
Цепочка методов особенно эффективна с такими грамматиками как parent::= (this | that)*. Использование различных методов обеспечивает читабельный способ увидеть, какой аргумент будет следующим. Точно так же необязательные аргументы могут быть легко пропущены с помощью метода Chaining. Список обязательных предложений, таких как parent::= first second, не очень хорошо работает с базовой формой, хотя он может хорошо поддерживаться с помощью прогрессивных интерфейсов. Большую часть времени я бы предпочел Nested Function для этого случая.
Самая большая проблема для Цепочки Методов - это проблема финишной обработки. Хотя существуют обходные пути, обычно, если вы натолкнетесь на это, вам лучше использовать вложенную функцию. Вложенная функция также является лучшим выбором, если вы попадаете в беспорядок с переменными контекста.
На мой взгляд, метод цепочки является чем-то новым. Конечно, это выглядит круто, но я не вижу в этом никаких реальных преимуществ.
Как:
someList.addObject("str1").addObject("str2").addObject("str3")
лучше чем:
someList.addObject("str1")
someList.addObject("str2")
someList.addObject("str3")
Исключением может быть ситуация, когда addObject() возвращает новый объект, и в этом случае код без цепочки может быть немного более громоздким, например:
someList = someList.addObject("str1")
someList = someList.addObject("str2")
someList = someList.addObject("str3")
Объединение методов может позволить непосредственно создавать расширенные DSL в Java. По сути, вы можете смоделировать по крайней мере следующие типы правил DSL:
1. SINGLE-WORD
2. PARAMETERISED-WORD parameter
3. WORD1 [ OPTIONAL-WORD]
4. WORD2 { WORD-CHOICE-A | WORD-CHOICE-B }
5. WORD3 [ , WORD3 ... ]
Эти правила могут быть реализованы с использованием этих интерфейсов
// Initial interface, entry point of the DSL
interface Start {
End singleWord();
End parameterisedWord(String parameter);
Intermediate1 word1();
Intermediate2 word2();
Intermediate3 word3();
}
// Terminating interface, might also contain methods like execute();
interface End {}
// Intermediate DSL "step" extending the interface that is returned
// by optionalWord(), to make that method "optional"
interface Intermediate1 extends End {
End optionalWord();
}
// Intermediate DSL "step" providing several choices (similar to Start)
interface Intermediate2 {
End wordChoiceA();
End wordChoiceB();
}
// Intermediate interface returning itself on word3(), in order to allow for
// repetitions. Repetitions can be ended any time because this interface
// extends End
interface Intermediate3 extends End {
Intermediate3 word3();
}
С помощью этих простых правил вы можете реализовать сложные DSL, такие как SQL, непосредственно в Java, как это делает jOOQ, библиотека, которую я создал. Смотрите довольно сложный пример SQL, взятый из моего блога здесь:
create().select(
r1.ROUTINE_NAME,
r1.SPECIFIC_NAME,
decode()
.when(exists(create()
.selectOne()
.from(PARAMETERS)
.where(PARAMETERS.SPECIFIC_SCHEMA.equal(r1.SPECIFIC_SCHEMA))
.and(PARAMETERS.SPECIFIC_NAME.equal(r1.SPECIFIC_NAME))
.and(upper(PARAMETERS.PARAMETER_MODE).notEqual("IN"))),
val("void"))
.otherwise(r1.DATA_TYPE).as("data_type"),
r1.NUMERIC_PRECISION,
r1.NUMERIC_SCALE,
r1.TYPE_UDT_NAME,
decode().when(
exists(
create().selectOne()
.from(r2)
.where(r2.ROUTINE_SCHEMA.equal(getSchemaName()))
.and(r2.ROUTINE_NAME.equal(r1.ROUTINE_NAME))
.and(r2.SPECIFIC_NAME.notEqual(r1.SPECIFIC_NAME))),
create().select(count())
.from(r2)
.where(r2.ROUTINE_SCHEMA.equal(getSchemaName()))
.and(r2.ROUTINE_NAME.equal(r1.ROUTINE_NAME))
.and(r2.SPECIFIC_NAME.lessOrEqual(r1.SPECIFIC_NAME)).asField())
.as("overload"))
.from(r1)
.where(r1.ROUTINE_SCHEMA.equal(getSchemaName()))
.orderBy(r1.ROUTINE_NAME.asc())
.fetch()
Другим хорошим примером является jRTF, небольшой DSL, разработанный для создания RTF-документов непосредственно в Java. Пример:
rtf()
.header(
color( 0xff, 0, 0 ).at( 0 ),
color( 0, 0xff, 0 ).at( 1 ),
color( 0, 0, 0xff ).at( 2 ),
font( "Calibri" ).at( 0 ) )
.section(
p( font( 1, "Second paragraph" ) ),
p( color( 1, "green" ) )
)
).out( out );
Это опасно, потому что вы можете зависеть от большего количества объектов, чем ожидалось, например, ваш вызов возвращает экземпляр другого класса:
Я приведу пример:
foodStore - это объект, который состоит из множества ваших продуктовых магазинов. foodstore.getLocalStore() возвращает объект, который содержит информацию о ближайшем хранилище к параметру. getPriceforProduct(что угодно) - это метод этого объекта.
Поэтому, когда вы вызываете foodStore.getLocalStore (параметры).getPriceforProduct(что угодно)
Вы зависите не только от FoodStore, но и от LocalStore.
Если getPriceforProduct(что-либо) когда-либо изменится, вам нужно изменить не только FoodStore, но и класс, который вызвал цепочечный метод.
Вы всегда должны стремиться к слабой связи между классами.
Это, как говорится, мне лично нравится цеплять их при программировании Ruby.
Многие используют цепочку методов для удобства, а не для удобства чтения. Цепочка методов приемлема, если она включает в себя выполнение одного и того же действия с одним и тем же объектом - но только если она действительно улучшает читабельность, а не только для написания меньшего количества кода.
К сожалению, многие используют цепочку методов в соответствии с примерами, приведенными в вопросе. Хотя их можно сделать читабельными, к сожалению, они вызывают высокую связь между несколькими классами, поэтому это нежелательно.
Преимущества цепочки
то есть, где я люблю его использовать
Одним из преимуществ цепочки, о котором я не упомянул, была возможность использовать его во время инициализации переменной или при передаче нового объекта в метод, не будучи уверенным, является ли это плохой практикой или нет.
Я знаю, что это надуманный пример, но скажем, у вас есть следующие классы
Public Class Location
Private _x As Integer = 15
Private _y As Integer = 421513
Public Function X() As Integer
Return _x
End Function
Public Function X(ByVal value As Integer) As Location
_x = value
Return Me
End Function
Public Function Y() As Integer
Return _y
End Function
Public Function Y(ByVal value As Integer) As Location
_y = value
Return Me
End Function
Public Overrides Function toString() As String
Return String.Format("{0},{1}", _x, _y)
End Function
End Class
Public Class HomeLocation
Inherits Location
Public Overrides Function toString() As String
Return String.Format("Home Is at: {0},{1}", X(), Y())
End Function
End Class
И скажем, у вас нет доступа к базовому классу, или Скажите, что значения по умолчанию являются динамическими, основанными на времени и т. Д. Да, вы можете создать экземпляр, затем изменить значения, но это может стать громоздким, особенно если вы просто передаете значения для метода:
Dim loc As New HomeLocation()
loc.X(1337)
PrintLocation(loc)
Но не проще ли это прочитать?
PrintLocation(New HomeLocation().X(1337))
Или как насчет ученика?
Public Class Dummy
Private _locA As New Location()
Public Sub New()
_locA.X(1337)
End Sub
End Class
против
Public Class Dummy
Private _locC As Location = New Location().X(1337)
End Class
Вот как я использовал цепочки, и обычно мои методы предназначены только для конфигурации, поэтому они имеют длину всего 2 строки, задайте значение, затем Return Me
, Для нас это вычистило огромные строки, которые очень трудно читать и понимать, в одну строку, которая читается как предложение. что-то вроде
New Dealer.CarPicker().Subaru.WRX.SixSpeed.TurboCharged.BlueExterior.GrayInterior.Leather.HeatedSeats
Что-то вроде
New Dealer.CarPicker(Dealer.CarPicker.Makes.Subaru
, Dealer.CarPicker.Models.WRX
, Dealer.CarPicker.Transmissions.SixSpeed
, Dealer.CarPicker.Engine.Options.TurboCharged
, Dealer.CarPicker.Exterior.Color.Blue
, Dealer.CarPicker.Interior.Color.Gray
, Dealer.CarPicker.Interior.Options.Leather
, Dealer.CarPicker.Interior.Seats.Heated)
Ущерб Цепи
то есть, где я не люблю его использовать
Я не использую цепочку, когда есть много параметров для передачи в подпрограммы, главным образом потому, что строки становятся очень длинными, и, как упоминалось в OP, это может сбить с толку, когда вы вызываете подпрограммы для других классов для передачи одному из методы сцепления.
Также существует опасение, что подпрограмма вернет недопустимые данные, поэтому до сих пор я использовал цепочку, только когда возвращаю тот же вызываемый экземпляр. Как указывалось, если вы создаете цепочку между классами, вы усложняете отладку (которая вернула ноль?) И можете увеличить взаимосвязь зависимостей между классами.
Заключение
Как и все в жизни и программировании, создание цепочек не является ни хорошим, ни плохим, если вы можете избежать плохого, то создание цепочек может принести большую пользу.
Я стараюсь следовать этим правилам.
- Старайтесь не связывать между классами
- Сделайте подпрограммы специально для цепочки
- Делать только одну вещь в цепочке
- Используйте его, когда это улучшает читабельность
- Используйте это, когда это делает код проще
Это кажется субъективным.
Метод цепочки не является чем-то плохим или хорошим по своей сути.
Читаемость это самая важная вещь.
(Также учтите, что наличие большого количества методов в цепочке сделает вещи очень хрупкими в случае изменения
В большинстве случаев цепочка методов может быть новинкой, но я думаю, что она имеет место. Один пример может быть найден в использовании Active Record CodeIgniter:
$this->db->select('something')->from('table')->where('id', $id);
Это выглядит намного чище (и, на мой взгляд, более разумно), чем:
$this->db->select('something');
$this->db->from('table');
$this->db->where('id', $id);
Это действительно субъективно; Каждый человек имеет свое собственное мнение.
Я вообще ненавижу цепочку методов, потому что я думаю, что это ухудшает читабельность. Компактность часто путают с удобочитаемостью, но они не совпадают. Если вы делаете все в одном утверждении, то это компактно, но в большинстве случаев оно менее читаемо (труднее следовать), чем в нескольких утверждениях. Как вы заметили, если вы не можете гарантировать, что возвращаемое значение используемых методов одинаково, то объединение методов будет источником путаницы.
1.)
participant
.addSchedule(events[1])
.addSchedule(events[2])
.setStatus('attending')
.save();
против
participant.addSchedule(events[1]);
participant.addSchedule(events[2]);
participant.setStatus('attending');
participant.save()
2.)
participant
.getSchedule('monday')
.saveTo('monnday.file');
против
mondaySchedule = participant.getSchedule('monday');
mondaySchedule.saveTo('monday.file');
3.)
participant
.attend(event)
.setNotifications('silent')
.getSocialStream('twitter')
.postStatus('Joining '+event.name)
.follow(event.getSocialId('twitter'));
против
participant.attend(event);
participant.setNotifications('silent')
twitter = participant.getSocialStream('twitter')
twitter.postStatus('Joining '+event.name)
twitter.follow(event.getSocialId('twitter'));
Как вы можете видеть, вы выигрываете почти ничего, потому что вам нужно добавить разрывы строк к вашему единственному выражению, чтобы сделать его более читабельным, и добавить отступ, чтобы было ясно, что вы говорите о разных объектах. Ну, если бы я хотел использовать язык на основе идентификаторов, то вместо этого я бы изучал Python, не говоря уже о том, что большинство IDE удаляют отступы путем автоматического форматирования кода.
Я думаю, что единственное место, где этот вид цепочки может быть полезен, - это передача потоков в CLI или объединение нескольких запросов в SQL. Оба имеют цену за несколько заявлений. Но если вы хотите решить сложные проблемы, вы в конечном итоге окажетесь даже у тех, кто платит цену и пишет код в нескольких выражениях с использованием переменных или написания сценариев bash и хранимых процедур или представлений.
Что касается СУХОЙ интерпретации: "Избегайте повторения знаний (не повторения текста)". и "Напечатывай меньше, даже не повторяй тексты", первое, что на самом деле означает этот принцип, но второе - это общее недоразумение, потому что многие люди не могут понять слишком сложную чушь, как "Каждый кусочек знания должен иметь один, однозначный, авторитетное представительство в системе ". Второй - это компактность любой ценой, что нарушает этот сценарий, поскольку ухудшает читаемость. Первая интерпретация нарушается DDD, когда вы копируете код между ограниченными контекстами, потому что слабая связь более важна в этом сценарии.
Я думаю, что основная ошибка - думать, что это вообще объектно-ориентированный подход, хотя на самом деле это скорее подход функционального программирования, чем что-либо еще.
Основными причинами, по которым я его использую, является удобочитаемость и предотвращение переполнения моего кода переменными.
Я не очень понимаю, о чем говорят другие, когда говорят, что это ухудшает читабельность. Это одна из наиболее сжатых и последовательных форм программирования, которые я когда-либо использовал.
Также это:
convertTextToVoice.LoadText ("source.txt") ConvertToVoice("destination.wav").
это то, как я обычно использую это. Я использую это, чтобы связать число параметров по x, как я обычно не использую. Если бы я хотел ввести x количество параметров в вызове метода, я бы использовал синтаксис params:
public void foo (params object [] items)
И приведите объекты на основе типа или просто используйте массив или коллекцию типов данных в зависимости от вашего варианта использования.
Абсолютно упущенный момент здесь заключается в том, что метод цепочки учитывает DRY. Это эффективный заменитель "с" (который плохо реализован в некоторых языках).
A.method1().method2().method3(); // one A
A.method1();
A.method2();
A.method3(); // repeating A 3 times
Это имеет значение по той же причине, что DRY всегда имеет значение; если A оказывается ошибкой, и эти операции необходимо выполнить на B, вам нужно обновить только в 1 месте, а не в 3.
С практической точки зрения преимущество в этом случае невелико. Тем не менее, немного меньше печатать, немного более устойчивый (сухой), я возьму его.
Я согласен, я изменил способ, которым свободный интерфейс был реализован в моей библиотеке.
До:
collection.orderBy("column").limit(10);
После:
collection = collection.orderBy("column").limit(10);
В реализации "before" функции модифицировали объект и завершились return this
, Я изменил реализацию, чтобы вернуть новый объект того же типа.
Мои аргументы в пользу этого изменения:
Возвращаемое значение не имело ничего общего с функцией, оно было просто для поддержки цепочки, согласно OOP это должна была быть функция void.
Цепочки методов в системных библиотеках также реализуют это (например, linq или string):
myText = myText.trim().toUpperCase();
Исходный объект остается неизменным, что позволяет пользователю API решать, что с ним делать. Это позволяет:
page1 = collection.limit(10); page2 = collection.offset(10).limit(10);
Реализация копии также может использоваться для создания объектов:
painting = canvas.withBackground('white').withPenSize(10);
Где
setBackground(color)
Функция изменяет экземпляр и ничего не возвращает (как предполагалось).Поведение функций более предсказуемо (см. Пункты 1 и 2).
Использование короткого имени переменной также может уменьшить помехи в коде, не применяя API в модели.
var p = participant; // create a reference p.addSchedule(events[1]);p.addSchedule(events[2]);p.setStatus('attending');p.save()
Заключение:
На мой взгляд, свободный интерфейс, который использует return this
реализация просто неправильно.
Мнения Ответ
Самым большим недостатком цепочки является то, что читателю может быть трудно понять, как каждый метод влияет на исходный объект, если да, и какой тип возвращает каждый метод.
Некоторые вопросы:
- Возвращают ли методы в цепочке новый объект или тот же объект изменен?
- Все ли методы в цепочке возвращают один и тот же тип?
- Если нет, то как отображается изменение типа в цепочке?
- Можно ли безопасно отбросить значение, возвращаемое последним методом?
На большинстве языков отладка действительно может быть сложнее с цепочкой. Даже если каждый шаг в цепочке находится на отдельной строке (что нарушает цель цепочки), может быть сложно проверить значение, возвращаемое после каждого шага, особенно для немутантных методов.
Время компиляции может быть медленнее в зависимости от языка и компилятора, поскольку выражения могут быть намного сложнее для разрешения.
Я считаю, что, как и во всем, цепочка - хорошее решение, которое может пригодиться в некоторых случаях. Его следует использовать с осторожностью, понимая последствия и ограничивая количество элементов цепочки до нескольких.
Хорошо:
- Это лаконично, но позволяет элегантно поместить больше в одну строку.
- Иногда вы можете избежать использования переменной, которая иногда может быть полезной.
- Это может работать лучше.
Плохо:
- Вы реализуете возвраты, по существу добавляя функциональность к методам объектов, что на самом деле не является частью того, что эти методы предназначены для выполнения. Он возвращает то, что у вас уже есть, чтобы сэкономить несколько байтов.
- Он скрывает переключение контекста, когда одна цепочка ведет к другой. Вы можете получить это с помощью геттеров, за исключением того, что это довольно ясно, когда контекст переключается.
- Цепочка из нескольких строк выглядит некрасиво, плохо сочетается с отступами и может вызвать некоторую путаницу в работе оператора (особенно в языках с ASI).
- Если вы хотите начать возвращать что-то еще, что полезно для связанного метода, вам, возможно, будет труднее исправить его или столкнуться с большим количеством проблем с ним.
- Вы перекладываете управление на сущность, которую обычно не переносите просто для удобства, даже в строго типизированных языках ошибки, вызванные этим, не всегда могут быть обнаружены.
- Это может работать хуже.
Генеральный:
Хороший подход состоит в том, чтобы не использовать цепочку в целом, пока не возникнут ситуации или не подойдут конкретные модули.
В некоторых случаях сцепление может сильно ухудшить читабельность, особенно при взвешивании в точках 1 и 2.
Применительно к этому может быть использовано не по назначению, например, вместо другого подхода (например, передача массива) или смешивания методов причудливыми способами (parent.setSomething(). GetChild(). SetSomething (). GetParent(). GetSomething()).
Что ж, я вижу одно из наиболее важных преимуществ цепочки методов: вам не нужно повторять вызовы одного и того же объекта для выполнения последовательных операций. Вы должны использовать его.
Запросы Linq — хороший пример цепочки методов, где типичный запрос выглядит следующим образом:
lstObjects
.Where(...)
.Select(...)
.OrderBy(...)
.ThenBy(...)
.ToList();
На мой взгляд, это довольно интуитивно понятно и позволяет избежать ненужных временных переменных для хранения частичных результатов, которые вряд ли могут вас заинтересовать.
Еще один тонкий момент, на который стоит обратить внимание, — это использование метода расширения «ThenBy», который доступен для вызова только после вызова метода «OrderBy» или «OrderByDescending». Это означает, что здесь также поддерживается внутреннее состояние, которое определяет, может ли быть вызван ThenBy или нет. И, как и в этом запросе, бывают случаи, когда клиентское приложение может быть не заинтересовано в сохранении внутреннего состояния во временной переменной, а может быть заинтересовано только в окончательных результатах.
Таким образом, при написании библиотеки, если мы хотим предоставить API, который дает представление о выполнении определенного набора операций в определенном порядке, тогда возможность объединения методов сделает использование библиотеки более интуитивным.
На типизированных языках (которых не хватает auto
или эквивалент), это избавляет разработчика от необходимости объявлять типы промежуточных результатов.
import Participant
import Schedule
Participant participant = new Participant()
... snip...
Schedule s = participant.getSchedule(blah)
s.saveTo(filename)
Для более длинных цепочек вы можете иметь дело с несколькими различными промежуточными типами, вам нужно будет объявить каждый из них.
Я считаю, что этот подход действительно разработан в Java, где а) все вызовы функций являются вызовами функций-членов и б) требуются явные типы. Конечно, здесь есть компромисс в терминах, когда теряется некоторая ясность, но в некоторых ситуациях некоторые люди считают это целесообразным.