На нашем сайте мы используем cookie для сбора информации технического характера и обрабатываем IP-адрес вашего местоположения. Продолжая использовать этот сайт, вы даете согласие на использование файлов cookies. Здесь вы можете узнать, как мы пользуемся файлами cookies.
Я согласен
логотип upread.ru

Law of Demeter (Закон Деметры, LOD) с примером на PHP



Этот закон часто используют вместе с темой Tell Don't Ask. Его идея в том, что объект должен обладать ограниченным знанием о других объектах и модулях, взаимодействовать только с теми, кто имеет к нему непосредственное отношение.



Формально правило звучит так, что в клиентском коде вы можете вызывать методы объектов, которые:

  • Были переданы как аргументы;
  • Были созданы локально;
  • Являются глобальными;
  • Собственные методы;
Пока что непонятно зачем это всё. Давайте разбираться.

Основная задача — создать условия для слабой связанности (loose coupling) между объектами. Но за счёт чего?

Представьте, вы находитесь в магазине, хотите купить товар стоимостью 25$. Вы дадите продавцу 25$ или вы отдадите продавцу свой кошелек, чтобы тот достал 25$? Давайте разберём этот пример

<php
declare(strict_types=1);


final class Wallet
{
    public function __construct(private Money $balance)
    {
    }

    public function subtract(Money $money): void
    {
        $this->balance = $this->balance->subtract($money);
    }
}

final class SomePerson
{
    public function __construct(
        private readonly Wallet $wallet,
    ) {
    }

    public function getWallet(): Wallet
    {
        return $this->wallet;
    }
}

#1
$somePerson = new SomePerson(new Wallet(Money::USD(100)));
$somePerson->getWallet()->subtract(Money::USD(25));


final class SomeAnotherPerson
{
    public function __construct(
        private readonly Wallet $wallet,
    ) {
    }

    public function subtractMoney(Money $money): void
    {
        $this->wallet->subtract($money);
    }
}

#2
$someAnotherPerson = new SomeAnotherPerson(new Wallet(Money::USD(100)));
$someAnotherPerson->subtractMoney(Money::USD(25));
В первом случае мы явно знаем, что у объекта SomePerson есть Wallet, который мы хотим получить, чтобы достать (вычесть) из него какую-то сумму денег. Таким образом мы создаём сильную связь (tight coupling) с объектом кошелька, а также раскрываем особенности внутренней реализации.

Чем же лучше второй вариант?

Когда у SomeAnotherPerson мы вызываем метод subtractMoney, это нам даёт дополнительную гибкость, возможность легко изменить внутреннюю реализацию данного метода, не изменяя другие участки кода. Как бонус появляется information hiding, а также это дело менее проблематично мокать в тестах.

LOD также называют законом "одной точки" (one dot), т.к. ноги растут из Java. В нашем же случае о его применении стоит задуматься при виде более одной стрелочки ->. Обращаю внимание, что речь идёт о методах (или свойствах), которые позволяют получить промежуточный объект, утрируя - о геттерах. То есть две стрелочки в каком нибудь fluent interface (напр. $filter->limit(10)->offset(0)) сюда не относятся.

У закона Деметры тоже есть свои минусы. Одним из них является необходимость создания большого количества методов-адаптеров. Если вы чувствуете, что классы становятся перегруженными - это признак плохого объектно-ориентированного дизайна.

Можно ли нарушать закон Деметры?

Руководствуйтесь здравым смыслом. Если у вас, например, вложенные DTO, которые предназначены для транспортировки объектов, то нет никакого смысла наворачивать что-то подобное сверху. Используйте только там, где это уместно и помните о преимуществах.



Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.



тегизаметки, php, теория программирования





Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Пишу программы на заказ Java
Что такое CNAME


© upread.ru 2013-2022
При перепечатке активная ссылка на сайт обязательна.
Задать вопрос
письмо
Здравствуйте! Вы можете задать мне любой вопрос. Если не получается отправить сообщение через эту форму, то пишите на почу up777up@yandex.ru
Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.