Фабричный метод может нарушать закон Деметры?

цитируя отсюда: https://en.wikipedia.org/wiki/Law_of_Demeter

Более формально, закон Деметры для функций требует, чтобы метод
m объекта O может вызывать только методы следующих
Объекты: [2]

  • О себе

  • параметры м

  • Любые объекты, созданные / созданные в течение м

  • Прямые составляющие объекты О

  • Глобальная переменная, доступная O, в
    размах м

В частности, объект должен избегать вызова методов члена
объект, возвращенный другим методом

так в деталях:

class O
{
private $c;
public function m($obj1)
{
$this->a(); // OK
$obj1->a(); // OK
(new C())->a(); // OK
$c->a(); // OK
$a = function() { };
$a(); // OK
}

private function a() {}
}

теперь третий закон сомнителен. Итак, я недавно создал объект. Но если я вместо

(new C())->a();

Я делаю:

$this->factory->createC()->a();

это все еще действует? Обычный класс был создан, но не new но заводской. Но эй! Закон гласил:

В частности, объект должен избегать вызова методов объекта-члена, возвращаемого другим методом

по этому правилу метод фабрики не работает! Что теперь? Это действительно терпит неудачу?

8

Решение

Я так не думаю.

Особенно это:

Любые объекты, созданные / созданные в м

Я бы применил это и к фабрике. Даже если строго конструктор объекта вызывается на фабрике, объект все еще создается, и особенно за м. Я бы интерпретировал фабрику как конструктор особого типа и посмотрел бы мимо того факта, что вы не видите new Ключевое слово там.

Учитывая различные важные роли, которые фабрики играют в разработке программного обеспечения (инверсия управления — одна из них), я думаю, что они слишком ценны, чтобы их отпустить. Лучше изменить вашу интерпретацию этого закона или того, что такое конструктор, и использовать эти фабрики, когда захотите.

6

Другие решения

Не следует слишком строго следовать правилам, которые вытекают из закона Деметры. Необходимо понять смысл и цель этого закона.
Соблюдение закона Деметры помогает нам избежать лишних зависимостей кода от внешних классов и компонентов. Один из принципов этого закона говорит нам следующее:

Каждый юнит должен иметь только ограниченные знания о других юнитах: только юниты, «тесно связанные» с текущим юнитом

В вашем примере O класс знает класс C в любом случае. Использование фабрики не влияет на этот факт. Так или иначе класс O зависит от класса C, и эта зависимость неизбежна. Это означает, что зависимость не является избыточной. На самом деле зависимость между классом C и классом O — это зависимость между «тесно связанными» единицами, поэтому не существует нарушения закона Деметры, если вы используете фабрику.

В качестве примера давайте представим следующий экземпляр кода:

class O
{

public function m()
{
$c = new C();
$c->a();
}
}

Как видите, O-класс знает класс C и зависит от него. Закон Деметры не нарушается в этом кодексе. Если вы измените этот пример следующим образом:

class O
{

protected function build()
{
return new C();
}

public function m()
{
$c = $this->build();
$c->a();
}
}

класс O все еще будет знать класс C и зависеть от него, закон Деметры не будет нарушен в этом коде. Фактически мы делегировали ответственность за создание объекта на фабричный метод. Если вы измените этот пример следующим образом:

class Factory
{
public function build()
{
return new C();
}
}

class O
{

/**
* @var Factory
*/
protected $factory;

public function m()
{
$c = $this->factory->build();
$c->a();
}
}

Мы делегировали ответственность за создание объекта на объект фабрики, но этот факт нарушил закон Деметра, потому что ничего не изменится в зависимостях между O-классом и C-классом. Как и в предыдущих случаях, класс O знает класс C и зависит от него.
У нас одинаковые зависимости во всех трех случаях.

4

По вопросам рекламы [email protected]