Во многих отношениях мне действительно нравится идея интерфейсов Fluent, но со всеми современными функциями C # (инициализаторы, лямбды, именованные параметры) я думаю, «стоит ли это того?» И «Правильный ли это шаблон для использовать?». Может ли кто-нибудь дать мне, если не принятую практику, хотя бы свой собственный опыт или матрицу решений о том, когда использовать шаблон Fluent?
Заключение:
Некоторые хорошие правила из ответов на данный момент:
- Свободные интерфейсы очень помогают, когда вы выполняете больше действий, чем сеттеры, так как вызовы получают больше пользы от сквозной передачи контекста.
- Свободные интерфейсы следует рассматривать как слой поверх API, а не как единственный способ использования.
- Современные функции, такие как лямбда-выражения, инициализаторы и именованные параметры, могут работать рука об руку, чтобы сделать гибкий интерфейс еще более дружественным.
Вот пример того, что я имею в виду под современными функциями, заставляющими его чувствовать себя менее нужным. Возьмем, к примеру, (возможно, плохой пример) интерфейс Fluent, который позволяет мне создать сотрудника, например:
Employees.CreateNew().WithFirstName("Peter")
.WithLastName("Gibbons")
.WithManager()
.WithFirstName("Bill")
.WithLastName("Lumbergh")
.WithTitle("Manager")
.WithDepartment("Y2K");
Можно легко написать с помощью инициализаторов, таких как:
Employees.Add(new Employee()
{
FirstName = "Peter",
LastName = "Gibbons",
Manager = new Employee()
{
FirstName = "Bill",
LastName = "Lumbergh",
Title = "Manager",
Department = "Y2K"
}
});
Я мог бы также использовать именованные параметры в конструкторах в этом примере.
Ответы:
Написание свободного интерфейса (я баловался с ним) требует больше усилий, но оно окупается, потому что, если вы все сделаете правильно, цель результирующего пользовательского кода будет более очевидной. По сути, это форма специфичного для домена языка.
Другими словами, если ваш код читается намного больше, чем написано (а какой код не является?), Тогда вы должны рассмотреть возможность создания свободного интерфейса.
Свободные интерфейсы - это больше контекст, и это гораздо больше, чем просто способы настройки объектов. Как вы можете видеть из приведенной выше ссылки, я использовал API-интерфейс fluent-ish для достижения следующих целей:
objectA.
intellisense, вы получаете много подсказок. В моем случае выше,plm.Led.
дает вам все возможности для управления встроенным светодиодом иplm.Network.
дает вам то, что вы можете сделать с сетевым интерфейсом.plm.Network.X10.
Дает вам подмножество сетевые действия для устройств X10. Вы не получите этого с инициализаторами конструктора (если вы не хотите создавать объект для каждого другого типа действия, что не является идиоматическим).Одна вещь, которую я обычно делаю, это:
Я не понимаю, как можно сделать что-то подобное без свободного интерфейса.
Изменить 2 : Вы также можете сделать действительно интересные улучшения читабельности, такие как:
источник
Скотт Хансельман рассказывает об этом в эпизоде 260 своего подкаста Hanselminutes с Джонатаном Картером. Они объясняют, что свободный интерфейс больше похож на пользовательский интерфейс API. Вы не должны предоставлять свободный интерфейс в качестве единственной точки доступа, а должны предоставлять ее как своего рода кодовый интерфейс поверх «обычного интерфейса API».
Джонатан Картер также немного рассказывает о дизайне API в своем блоге .
источник
Свободные интерфейсы - это очень мощные функции, которые могут быть предоставлены в контексте вашего кода при «правильных» рассуждениях.
Если ваша цель состоит в том, чтобы просто создать массивные однострочные цепочки кода как своего рода псевдо-черный ящик, то вы, вероятно, лаете не на то дерево. Если, с другой стороны, вы используете его, чтобы повысить ценность своего интерфейса API, предоставляя средства для цепочки вызовов методов и улучшения читабельности кода, то, потратив на это много хорошего планирования и усилий, я думаю, что усилия того стоят.
Я бы не стал следовать тому, что, по-видимому, становится общим «шаблоном» при создании беглых интерфейсов, когда вы называете все свои беглые методы «с» чем-то, так как он лишает потенциально хороший API-интерфейс своего контекста и, следовательно, его внутреннюю ценность ,
Ключ в том, чтобы думать о свободном синтаксисе как о конкретной реализации языка, специфичного для предметной области. В качестве действительно хорошего примера того, о чем я говорю, взгляните на StoryQ, который использует беглость как средство выражения DSL очень ценным и гибким способом.
источник
position.withX(5)
сравнениюposition.getDistanceToOrigin()
Начальное замечание: я не согласен с одним допущением в этом вопросе и делаю из этого свои конкретные выводы (в конце этого поста). Поскольку это, вероятно, не дает полного, всеобъемлющего ответа, я отмечаю это как CW.
На мой взгляд, эти две версии должны означать и делать разные вещи.
В отличие от нелегальной версии, свободная версия скрывает тот факт, что новый
Employee
также добавленAdd
в коллекциюEmployees
- он только предполагает, что новый объект -Create
d.Значение слова
….WithX(…)
неоднозначно, особенно для людей, пришедших из F #, у которого естьwith
ключевое слово для выражений объекта : они могут интерпретироватьсяobj.WithX(x)
как новый объект, производный отobj
которого идентичен, заobj
исключением егоX
свойства, значение которого равноx
. С другой стороны, со второй версией ясно, что никакие производные объекты не создаются, и что все свойства указаны для исходного объекта.Это
….With…
имеет еще одно значение: переключение «фокуса» инициализации свойства на другой объект. Тот факт, что ваш свободный API имеет два разных значения,With
затрудняет правильную интерпретацию происходящего ... возможно, поэтому вы использовали отступ в своем примере, чтобы продемонстрировать предполагаемое значение этого кода. Было бы понятнее, как это:Выводы: «Скрытие» достаточно простой языковой функции
new T { X = x }
с помощью свободного API (Ts.CreateNew().WithX(x)
), очевидно, может быть сделано, но:Необходимо позаботиться о том, чтобы читатели полученного беглого кода все еще понимали, что именно он делает. То есть, свободный API должен быть прозрачным по смыслу и однозначным. Разработка такого API может оказаться более трудоемкой, чем ожидалось (возможно, его придется проверить на простоту использования и принятия) и / или…
его разработка может потребовать больше усилий, чем необходимо: в этом примере свободный API добавляет очень мало «удобства пользователя» по сравнению с базовым API (языковая функция). Можно сказать, что свободный API должен сделать базовую функцию API / языка «более легкой в использовании»; то есть это должно сэкономить программисту значительное количество усилий. Если это просто другой способ написать то же самое, то, вероятно, оно того не стоит, потому что это не облегчает жизнь программиста, а только усложняет работу дизайнера (см. Вывод № 1 справа выше).
Обе точки выше молча предполагают, что свободный API является слоем поверх существующего API или языковой функции. Это предположение может быть еще одним хорошим руководством: свободный API может быть дополнительным способом сделать что-то, а не единственным. То есть, возможно, было бы неплохо предложить свободный API в качестве «выбора».
источник
Мне нравится свободный стиль, он выражает намерение очень четко. В примере с инициализатором объекта, который у вас есть после, вы должны иметь установщики общедоступных свойств, чтобы использовать этот синтаксис, а вы не используете свободный стиль. Скажем так, с вашим примером вы не сильно выигрываете у общедоступных сеттеров, потому что вы почти выбрали стиль метода java-esque set / get.
Что подводит меня ко второму пункту, я не уверен, что буду использовать свободный стиль, как у вас, с большим количеством установщиков свойств, я бы, вероятно, использовал вторую версию для этого, я нахожу его лучше, когда вы есть много глаголов, чтобы связать вместе, или, по крайней мере, много дел, а не настройки.
источник
Я не был знаком с термином беглый интерфейс , но он напоминает мне пару API, которые я использовал, включая LINQ .
Лично я не вижу, как современные функции C # могут помешать полезности такого подхода. Я бы скорее сказал, что они идут рука об руку. Например, с помощью методов расширения еще проще достичь такого интерфейса .
Возможно, поясните свой ответ, приведя конкретный пример того, как можно заменить свободный интерфейс с помощью одной из современных функций, которые вы упомянули.
источник