Comments 27
http://www.yegor256.com/2016/07/18/law-of-demeter.html
Я в свое время думал написать плагин для LLVM, который бы делал проверку этого закона, но предварительные эксперименты по внедрению такой проверки в стандарты кодирования провалились. Причиной тому была не чистая функциональность используемых языков программирования (в данном случае это были C++ и Python) — из-за того, что объекты можно передавать по ссылке, контролировать операции над ними не представлялось возможным (особенно, если это были библиотечные вызовы). В итоге мы использовали другие критерии, как например, тестируемость кода и ограничение cyclomatic complexity.
По-моему, в ней нет ничего альтернативного. Лишь более правильная интерпретация, чем наиболее распространённая. В приведённом там примере использование метода textOfLastPage()
не устраняет необходимость вызывающего кода знать внутреннее устройство вызываемого объекта. Ведь этот метод не может в какой-то момент начать возвращать текст первой страницы вместо последней… или вообще не текст, а число, обозначающее количество слов на странице. Для этого метод придётся переименовать, поскольку внутреннее устройство и реализация закодированы прямо в его названии.
Зависимость от Wallet в методе sell — это как раз то, от чего мы пытались уйти.
Метод нужен для осуществления продажи и должен зависеть от денег, но никак не от хранилища денег.
Если метод sell требует Money — это проблема дизайна.
Не знаю, почему у вас sell возвращает остаток денег в кошельке. Обычно при продаже формируется чек. Там есть не только деньги, но и счета списания и зачисления.
Где у вас защита от race condition?
Вы говорите о первом примере, который является примером того, как делать не нужно. Второй (более корректный пример) взаимодействует только с деньгами и возвращает сдачу.
> Обычно при продаже формируется чек
> Где у вас защита от race condition?
Цель этой статьи — показать пользу от применения закона в отдельно взятом, выдуманном случае. Этот случай недостаточно реален для того, чтобы он ровно в таком же виде возник у вас на проекте, но достаточно реален для того, чтобы из него можно было сделать какие-то выводы.
Я не ставил перед собой цели писать thread-safe пример, т.к. лишние строчки обработки race-condition'ов отвлекали бы читателя от основной мысли, которую я хотел донести. Я считаю, что это допустимо в рамках примера, хотя, возможно, следовало упомянуть об этом в начале статьи.
Всё же статья смотрелась бы серьёзнее, если бы пример был не выдуманный, а реальный. Меня, например, статья не убедила, что преобразования сделали код лучше.
У вас бизнес-процесс поменялся, что это стало «сдачей»? Сдача не с содержимого кошелька, а с одной из купюр из кошелька. У вас в примере не сдача.
Я напомню, что тред начался с «А что делать если метод sell требует и Wallet и Money?». И иметь и то и другое — нормально, если это не отдельно взятый выдуманный случай.
Если вы выдумываете плохие примеры — не надо с других спрашивать нормальные.
Зачем объекту Seller знать сколько денег находится в кошельке и тем более пытаться самому их оттуда извлечь, если его дело — посчитать суммарную стоимость всех продуктов и сказать «кошельку», сколько тот должен заплатить.
Хотя, конечно, продавец скорее должен взаимодействовать с покупателем, а вовсе не с его кошельком напрямую.
public Money sell(Set<Product> products, Wallet wallet) throws NotEnoughMoneyException
в отличие от
public Money sell(Set<Product> products, Money moneyForProducts) throws NotEnoughMoneyException
когда априори, изменяться нечему
В первом случае по-хорошему состояние изменяться должно, потому что метод называется sell
. То что оно не меняется, очень странно.
Второй метод sell
, который производит вычитание, по факту ничего не продаёт. Он мне нравится ещё меньше, чем первый, потому что непонятно, зачем он такой нужен.
А вообще спорные вопросы вроде изменяется ли передаваемый объект, стоит аккуратно расписывать в JavaDoc. Тогда всё будет хорошо.
1) приводимый пример автором мне показался больше академическим, нежели боевым, иначе тогда нужно упомянуть вопросы логирования, рейс-кондишина, отката и др. 2) первый вариант показался бы странным, если объект Wallet был неизменяемым, если же он изменяемый, то зачем тогда возвращать остаток? Но все равно, теперь вы заставили меня сомневаться, что лучше?
Закон Деметры