工厂方法可能违反Demeter法吗?

时间:2018-11-28 22:55:26

标签: php oop factory law-of-demeter

从这里引用: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实例化。但是,嘿!法律说:

  

特别是,对象应避免调用另一个方法返回的成员对象的方法

根据此规则,工厂方法将失败!怎么办?它真的失败了吗?

2 个答案:

答案 0 :(得分:6)

我不这样认为。

尤其是:

  

m

内创建/实例化的任何对象

我也会将其应用于工厂。即使严格在工厂中调用对象的构造函数,该对象仍然是由其构造的,尤其是 for m 。我会把工厂解释为一种特殊的构造函数,然后回过头来看到一个new关键字这一事实。

鉴于工厂在软件设计中所扮演的各种重要角色(控制反转是其中之一),我认为它们太有价值了,无法放手。最好更改您对此法或构造函数的解释,并在需要时使用这些工厂。

答案 1 :(得分:4)

对源自Demeter定律的规则不要太严格地遵循。有必要了解该法律的含义和目的。 遵守Demeter定律有助于我们避免代码对外部类和组件的过度依赖。该法律的原则之一告诉我们以下内容:

  

Each unit should have only limited knowledge about other units: only units "closely" related to the current unit

在您的示例中,无论如何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类并对其具有依赖性。 在所有三个实例中,我们都有相同的依赖项。