Comments 21
Сеттеры — это зло. Это следствие того, что в языках просто нет свойств, так что любое присвоение невозможно переопределить просто так, без лишних километров кода. И пришли они в пхп из мира джавы, да.
Но само существование сеттеров намекает на анемичность и неполноценность модели предметной области, и использование оных можно одобрить лишь в DTO и ValueObject, в любых остальных случаях рекомендуется «behaviour style», т.е. ориентированность на поведение, желательно вместо с поддержкой ISP.
Но само существование сеттеров намекает на анемичность и неполноценность модели предметной области, и использование оных можно одобрить лишь в DTO и ValueObject, в любых остальных случаях рекомендуется «behaviour style», т.е. ориентированность на поведение, желательно вместо с поддержкой ISP.
Что значит сеттеры зло?
Помимо установления значения функция может выполнять и другие действия, например, высчитывать какие-то внутренние состояния или переменные, чтобы не считать их каждый раз, когда они нужны.
Помимо установления значения функция может выполнять и другие действия, например, высчитывать какие-то внутренние состояния или переменные, чтобы не считать их каждый раз, когда они нужны.
Помимо установления значения функция может выполнять и другие действия, например, высчитывать какие-то внутренние состояния или переменные
Справедливости ради — обработчик проперти может делать то же самое.
Ну то и значит. Сеттеры — это плохо для любой предметной логики. А если метод выполняет ещё какую-то логику, то тем более.
В любом случае, чуть дополню своё довольно категоричное утверждение на счёт «сеттеры зло». Потому что судя по всему (судя по количеству минусаторов) — это моё утверждение восприняли с точки зрения иммутабельности данных, а не с точки зрения абстракции.
Сеттеры, кто бы что не говорил, но раскрывают инкапсуляцию (как и геттеры, кстати). Что бы понимать — инкапсуляция включает в себя и абстракцию от реализации в том числе. Прокидывание get/set наверх — это как торчащие кишки реализации наружу, когда реализация меняется — придётся менять и эти самые get/set, а так не должно быть. Интерфейс не должен меняться. Это отличет как раз хороший код от плохого.
Помимо этого можно вспомнить труды, например, Эрика Эванса для понимания принципов предметно-ориентированного программирования. Т.е. DDD. Ну и ещё с SOLID тоже. Принцип Open-Close никто не отменял.
P.S. Помимо этого стоит отметить, что я в первом своём комментарии упоминал на счёт DTO — это как раз и есть тот самый инструмент (точнее структура данных), которая должна быть абсолютно «тупой», где реализация свойств (т.е. get + set для данных) допускается и желательна, т.к. он и существует для того, чтобы хранить и передавать эти самые данные. С VO чуть сложнее, но по-моему сеттеры там не всегда будут мешать, хотя я бы воздержался, т.к. это всё же часть предметной области.
Пара примеров
Вопрос на засыпку:
Ожидается ли какая-то дополнительная логика в этом методе, кроме почты? Кажется, что нет. Если она есть — это пример плохо спроектированного интерфейса взаимодействия.
А теперь вот так:
Уже становится понятно, что это обновление почты, помимо установки значения, ещё может поменяться флаг подтверждения почты в false и отправиться письмо поверх нужного транспорта (хотя это уже пример высокой связанности, я бы так не рекомендовал писать всё же).
$user->setEmail('email@example.com');
Ожидается ли какая-то дополнительная логика в этом методе, кроме почты? Кажется, что нет. Если она есть — это пример плохо спроектированного интерфейса взаимодействия.
А теперь вот так:
$user->updateEmail('email@example.com');
// Или лучше даже так, например:
$transport = new SmtpTransport();
$user->updateEmail('email@example.com', $transport);
Уже становится понятно, что это обновление почты, помимо установки значения, ещё может поменяться флаг подтверждения почты в false и отправиться письмо поверх нужного транспорта (хотя это уже пример высокой связанности, я бы так не рекомендовал писать всё же).
В любом случае, чуть дополню своё довольно категоричное утверждение на счёт «сеттеры зло». Потому что судя по всему (судя по количеству минусаторов) — это моё утверждение восприняли с точки зрения иммутабельности данных, а не с точки зрения абстракции.
Сеттеры, кто бы что не говорил, но раскрывают инкапсуляцию (как и геттеры, кстати). Что бы понимать — инкапсуляция включает в себя и абстракцию от реализации в том числе. Прокидывание get/set наверх — это как торчащие кишки реализации наружу, когда реализация меняется — придётся менять и эти самые get/set, а так не должно быть. Интерфейс не должен меняться. Это отличет как раз хороший код от плохого.
Помимо этого можно вспомнить труды, например, Эрика Эванса для понимания принципов предметно-ориентированного программирования. Т.е. DDD. Ну и ещё с SOLID тоже. Принцип Open-Close никто не отменял.
P.S. Помимо этого стоит отметить, что я в первом своём комментарии упоминал на счёт DTO — это как раз и есть тот самый инструмент (точнее структура данных), которая должна быть абсолютно «тупой», где реализация свойств (т.е. get + set для данных) допускается и желательна, т.к. он и существует для того, чтобы хранить и передавать эти самые данные. С VO чуть сложнее, но по-моему сеттеры там не всегда будут мешать, хотя я бы воздержался, т.к. это всё же часть предметной области.
Нда, не стоит так говорить. Если бы изучали не только PHP знали бы чуточку больше. Использование свойств часто вносит неясность, хорошего тоже мало. Особенно когда вылетает исключение в свойстве, очень весело.
Ну я наверное криво выразился. Вначале я хотел описать историческую ремарку о появлении самого понятия «геттеров» и «сеттеров». А потом, во втором абзаце, раскрыть мысль почему торчать наружу данными — это плохо.
И только после вашего этого замечания понял, что мой комментарий можно воспринимать как «вот если бы свойства были, то вот прям зажили бы».
Нет, я хотел лишь сказать, что раскрывать инкапсуляцию — это плохо, а getSome и setSome — это тоже самое, что и писать «public $field;» внутри классов.
И только после вашего этого замечания понял, что мой комментарий можно воспринимать как «вот если бы свойства были, то вот прям зажили бы».
Нет, я хотел лишь сказать, что раскрывать инкапсуляцию — это плохо, а getSome и setSome — это тоже самое, что и писать «public $field;» внутри классов.
Ты молодец, конечно, что открываешь для себя азы программирования. Но, может не стоит по каждому пустяку строчить статью?
Позже я нашёл статью про Fluent Interface, где мне попался более приятный глазу пример на python.
Извините, но для питониста подобный код выглядит не приятно, а дико. В Python, во-первых, считается хорошим тоном придерживаться CQS, а чейнинг нарушает CQS. Во-вторых, в Python есть нормальные свойства (
@property
), поэтому геттерам-сеттерам в нём нет оправданий. Хотя геттеры-сеттеры − это вообще-то антипаттерн для любого языка, даже для Java. Тем более в таком количестве, чтобы их чейнить ради читаемости. Тут проблемы в проектировании, а не в читаемости.давно видел такое, по сути билдер. Но то что это называется «fluent setter» впервые слышу, спасибо!
Fluent interface в общем случае (setter — частный случай) — паттерн/парадигма в программировании, которая местами успешно используется. Например, LINQ в дотнете основан на этой идее, а поверх неё даже DSL свой сделан.
Нет, суть билдера вообще не в этом. Fluent — это сахар. А суть в создании иммутабельного объекта из разрозненных данных.
Всю жизнь так делаю, а сейчас выяснилось, что это fluent называется.
ocramius.github.io/blog/fluent-interfaces-are-evil
- break Encapsulation
- break Decorators/Composition
- harder to Mock
- make diffs harder to read
- less readable (personal feeling)
- cause BC breaks during early development stages
Fluent-сеттеры придуманы, чтобы код стал понятнее и чище.спорное утверждение.
Если такие последовательности форматировать, то получаем последовательный код, вид в профиль, а если нет, то длинные цепочки, скрывающиеся за правым краем окна редактора.
Для тривиальных вызовов такой подход возможно удобен, а стоит замаячить на горизонте ошибкам, и удобство сразу становится не столь очевидным.
Текучий интерфейс (англ. fluent interface) в разработке программного обеспечения — способ реализации объектно-ориентированного API, нацеленный на повышение читабельности исходного кода программы. Название придумано Эриком Эвансом и Мартином Фаулером.
© Кто-то в Wiki
© Кто-то в Wiki
Sign up to leave a comment.
Что такое fluent-сеттер