Сегодня в PhpStorm я создал приватную переменную и заметил, что IDE предлагает мне создать два вида сеттера: обычный setter и fluent setter.
Термин «fluent setter» мне раньше не встречался, поэтому я создал оба варианта.
/* PHP */
class Foo {
private $var;
// Обычный setter
public function setVar($var) {
$this->var = $var;
}
// Это fluent setter
public function setVar($var) {
$this->var = $var;
return $this;
}
}
Ага, значит, fluent setter, — это сеттер, который возвращает сам объект.
Какая глупость. Кому может понадобиться конструкция вида
$object = $object->setVar(1);
// Это же то же самое, что и просто
$object->setVar(1);
// И даже если создавать новую переменную, польза сомнительная
$sameObject = $object->setVar(1);
Это на первый взгляд.
Чуть позже я догадался. Это то, что называют чейнингом в jQuery. Благодаря возвращённому объекту, мы можем сразу применить следующий сеттер.
/* Javascript */
$('#elementId').val(13).css('font-size', '20px').appendTo(element2);
// И в столбик мне нравится:
$('#elementId')
.val(13)
.css('font-size', '20px')
.appendTo(element2);
Fluent-сеттеры придуманы, чтобы код стал понятнее и чище.
Да, в Javascript это заметно. В Java и PHP — тоже. Тем более, там и так активно используются функции-сеттеры, так почему бы не делать их в fluent-варианте.
/* php */
$car->setColor('#f00')->setWeight('1200')->setPower(55000);
$car
->setColor('#f00')
->setWeight('1200')
->setPower(55000);
в Python, конечно, можно написать функции-сеттеры, но польза от них не очевидная. Мне лично будет удобнее использовать обычный питоновский сеттер, который выглядит не как функция, а как оператор присваивания. Делать же сеттеры вида set_var() в Python, на мой взгляд, противоречит питоновским идеям простоты.
# python
# обычные @property
car.color = '#f00'
car.weight = 1200
car.power = 55000
# fluent-сеттеры, которые выглядят как функции. Так разве лучше? Лично меня смущает.
car.color('#f00').weight('1200').power(55000)
# Да и так тоже не лучше...
car.set_color('#f00').set_weight('1200').set_power(55000)
# Если писать в столбик, то надо слэши добавлять, и это ещё страшнее выглядит.
car.set_color('#f00') .set_weight('1200') .set_power(55000)
Позже я нашёл статью про Fluent Interface, где мне попался более приятный глазу пример на python.
Минутка самообразования закончена.
SerafimArts
Сеттеры — это зло. Это следствие того, что в языках просто нет свойств, так что любое присвоение невозможно переопределить просто так, без лишних километров кода. И пришли они в пхп из мира джавы, да.
Но само существование сеттеров намекает на анемичность и неполноценность модели предметной области, и использование оных можно одобрить лишь в DTO и ValueObject, в любых остальных случаях рекомендуется «behaviour style», т.е. ориентированность на поведение, желательно вместо с поддержкой ISP.
konshyn
Что значит сеттеры зло?
Помимо установления значения функция может выполнять и другие действия, например, высчитывать какие-то внутренние состояния или переменные, чтобы не считать их каждый раз, когда они нужны.
argentumbolo
Справедливости ради — обработчик проперти может делать то же самое.
SerafimArts
Ну то и значит. Сеттеры — это плохо для любой предметной логики. А если метод выполняет ещё какую-то логику, то тем более.
Ожидается ли какая-то дополнительная логика в этом методе, кроме почты? Кажется, что нет. Если она есть — это пример плохо спроектированного интерфейса взаимодействия.
А теперь вот так:
Уже становится понятно, что это обновление почты, помимо установки значения, ещё может поменяться флаг подтверждения почты в false и отправиться письмо поверх нужного транспорта (хотя это уже пример высокой связанности, я бы так не рекомендовал писать всё же).
AxisPod
Нда, не стоит так говорить. Если бы изучали не только PHP знали бы чуточку больше. Использование свойств часто вносит неясность, хорошего тоже мало. Особенно когда вылетает исключение в свойстве, очень весело.
SerafimArts
Ну я наверное криво выразился. Вначале я хотел описать историческую ремарку о появлении самого понятия «геттеров» и «сеттеров». А потом, во втором абзаце, раскрыть мысль почему торчать наружу данными — это плохо.
И только после вашего этого замечания понял, что мой комментарий можно воспринимать как «вот если бы свойства были, то вот прям зажили бы».
Нет, я хотел лишь сказать, что раскрывать инкапсуляцию — это плохо, а getSome и setSome — это тоже самое, что и писать «public $field;» внутри классов.
KevlarBeaver
Ты молодец, конечно, что открываешь для себя азы программирования. Но, может не стоит по каждому пустяку строчить статью?
Survtur Автор
Не для всех термин fluent setter входит в азы.
KevlarBeaver
Почитай про fluent interface в программировании. Сеттеры — лишь частный случай.
Tanner
Извините, но для питониста подобный код выглядит не приятно, а дико. В Python, во-первых, считается хорошим тоном придерживаться CQS, а чейнинг нарушает CQS. Во-вторых, в Python есть нормальные свойства (
@property
), поэтому геттерам-сеттерам в нём нет оправданий. Хотя геттеры-сеттеры ? это вообще-то антипаттерн для любого языка, даже для Java. Тем более в таком количестве, чтобы их чейнить ради читаемости. Тут проблемы в проектировании, а не в читаемости.Survtur Автор
Спасибо, что указали на ошибку. Конечно вместо «обычные сеттеры» я имел в виду «обычные property».
Tanner
Я не хотел вас поправлять в том, как называются разные фичи ЯП. Я имел в виду, что не сто?ит ровнять все ЯП под одну гребёнку. Fluent Interface нерелевантен для Python.
MeGaPk
давно видел такое, по сути билдер. Но то что это называется «fluent setter» впервые слышу, спасибо!
KevlarBeaver
Fluent interface в общем случае (setter — частный случай) — паттерн/парадигма в программировании, которая местами успешно используется. Например, LINQ в дотнете основан на этой идее, а поверх неё даже DSL свой сделан.
zagayevskiy
Нет, суть билдера вообще не в этом. Fluent — это сахар. А суть в создании иммутабельного объекта из разрозненных данных.
NickyX3
Всю жизнь так делаю, а сейчас выяснилось, что это fluent называется.
garex
ocramius.github.io/blog/fluent-interfaces-are-evil
Survtur Автор
Но всё же jQuery очень удобен (personal feeling)
Zanak
Если такие последовательности форматировать, то получаем последовательный код, вид в профиль, а если нет, то длинные цепочки, скрывающиеся за правым краем окна редактора.
Для тривиальных вызовов такой подход возможно удобен, а стоит замаячить на горизонте ошибкам, и удобство сразу становится не столь очевидным.
Survtur Автор
Текучий интерфейс (англ. fluent interface) в разработке программного обеспечения — способ реализации объектно-ориентированного API, нацеленный на повышение читабельности исходного кода программы. Название придумано Эриком Эвансом и Мартином Фаулером.
© Кто-то в Wiki
Zanak
Из вашего же источника: