从这里引用:https://en.wikipedia.org/wiki/Law_of_Demeter
更正式地说,功能的德米特定律要求一种方法 对象O的m只能调用以下类型的方法 对象:[2]
O本身
m的参数
在m内创建/实例化的任何对象
O的直接组成对象
- 的范围
在 m
尤其是,对象应避免调用成员的方法 其他方法返回的对象
因此,详细信息:
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
实例化。但是,嘿!法律说:
特别是,对象应避免调用另一个方法返回的成员对象的方法
根据此规则,工厂方法将失败!怎么办?它真的失败了吗?
答案 0 :(得分:6)
我不这样认为。
尤其是:
在 m
内创建/实例化的任何对象
我也会将其应用于工厂。即使严格在工厂中调用对象的构造函数,该对象仍然是由其构造的,尤其是 for m 。我会把工厂解释为一种特殊的构造函数,然后回过头来看到一个new
关键字这一事实。
鉴于工厂在软件设计中所扮演的各种重要角色(控制反转是其中之一),我认为它们太有价值了,无法放手。最好更改您对此法或构造函数的解释,并在需要时使用这些工厂。
答案 1 :(得分:4)
对源自Demeter定律的规则不要太严格地遵循。有必要了解该法律的含义和目的。 遵守Demeter定律有助于我们避免代码对外部类和组件的过度依赖。该法律的原则之一告诉我们以下内容:
在您的示例中,无论如何O类都知道C类。使用工厂不会影响这一事实。 O类或其他O类以某种方式依赖于C类,这种依赖是不可避免的。这意味着依赖性并不多余。实际上,C类和O类之间的依赖关系是“紧密”相关单元之间的依赖关系,因此,如果使用工厂,就不会违反Demeter的定律。
作为示例,让我们想象以下代码实例:
class O
{
public function m()
{
$c = new C();
$c->a();
}
}
如您所见,O类了解C类并对其具有依赖性。此代码未违反Demeter的法律。如果您要像下面那样修改此示例:
class O
{
protected function build()
{
return new C();
}
public function m()
{
$c = $this->build();
$c->a();
}
}
class O仍然会知道C类并依赖它,在此代码中不会违反Demeter的定律。实际上,我们将对象制作的责任委托给了工厂方法。如果您要像下面那样修改此示例:
class Factory
{
public function build()
{
return new C();
}
}
class O
{
/**
* @var Factory
*/
protected $factory;
public function m()
{
$c = $this->factory->build();
$c->a();
}
}
我们将对象制作的责任委托给了工厂对象,但是这个事实违反了Demeter的定律,因为在O类和C类之间的依存关系不会改变。作为上一个实例,O类知道C类并对其具有依赖性。 在所有三个实例中,我们都有相同的依赖项。