为什么需要构造函数?

迪马杂志

假设:(1)有一个带有构造函数的类,该类的方法使用注入的对象,例如:

class SomeClass
{
    protected $object1;
    protected $object2;

    public function __construct(
        Object1Interface $object1,
        Object2Interface $object2
    ) {
        $this->object1 = $object1;
        $this->object2 = $object2;
    }

// methods that use Object1 and Object2 classes by $this->object1 and $this->object2.
}

(2)那里是同一个类,没有构造函数,但类方法接受Object1Object2作为依赖项,如下所示:

class SomeClass
{
    public function doStuff1(Object1Interface $object1)
    {// do the stuff}

    public function doStuff2(Object2Interface $object2)
    {// do the stuff}
}

互联网上有许多倡导第一种变体的例子。

但是这些之间有什么区别?

Xerkus

它们是不同的,并不是真正地相互倡导。

(1)被广泛称为构造函数依赖注入。与setter依赖项注入相比,它是更好的首选形式,而不是(2)。这些依赖关系对使用者是“隐藏的”,并且通常在对象生存期内不会更改。

考虑抽象的http客户端:

$httpClient = new HttpClient(new CurlAdapter());
// or
$httpClient = new HttpClient(new SocketAdapter());

交换适配器不会影响客户端的使用方式:

$response = $httpClient->get($url);

提倡构造函数DI优于setter,因为它强制注入了依赖项。此外,设置器通常允许在对象生命周期内更改依赖项,从而改变其行为并为棘手且难以调试的错误打开可能性。

$dataContainer = $serviceLocator->get('SomeDataContainer');
$dataContainer->setStorage(new ArrayStorage());
$dataContainer->set('a','b');
$dataContainer->get('a'); // => 'b'
    // called somewhere else
    {
    $serviceLocator
        ->get('SomeDataContainer')
        ->setStorage(new RedisStorage());
    }
$dataContainer->get('a'); // => 'foobar' WAT

(2)用于不同的用例,通常不与DI重叠。有多种原因可以通过这种方式传递依赖关系。它们可能是交互界面的一部分,经常在对象生命周期内更改,或者在调用时确定。依赖关系在概念上可能并不属于对象,但特定操作仍然需要依赖关系。重要的是不要将它们存储在对象中并以可能引起副作用的方式使用!

class SomeClass
{
    protected $dep;

    public function doSomething(DepInterface $dep)
    {
        // do the stuff
        // store dep for later
        $this->dep = $dep;
        // This is similar to issue with setters but much worse.
        // Side effect is not obvious
    }

    public function doSomethingElse()
    {
       $this->dep->increment();
    }
}

for ($i = 0; $i < 100; $i++) {
   $foo->doSomething($bar);
   if (rand(0, 100) == $i) {
       // represents conditions out of direct control.
       // such as conditional or timing errors, alternative flows,
       // unanticipated code changes
       $foo->doSomethng($baz);
   }
   $foo->doSomethingElse();
}
// what will be the result?

考虑这个DDD示例,它解决了一些不切实际的问题:

class Bus
{
    public function board(Passenger $passenger, TicketingService $tservice)
    {
        // @todo check bus have seats
        // throws exception if ticket is invalid
        $tservice->punchPassengerTicket($this, $passenger);
        $this->passengers[] = $passenger;
    }
}

if ($bus->isIntercity()) {
    $ticketingService = new BookingService();
} else {
    $ticketingService = new PrepaidCityTransportCardsService();
} 
$bus->board($passenger, $ticketingService);

在此示例中,我们明确要求登机总线要求票证,并在登机时对票证进行打孔。但是,如果我们要在总线实例化时注入TicketingService,即使在根本没有上车的情况下,我们也会得到更加复杂的依赖关系图。通过服务执行操作,但从不存储它,可以在很大程度上降低复杂性并显着提高可测试性。

这种技术被称为领域驱动设计方面双重分派(不要与混淆双重分派),并广泛使用。
您可能会认为我们本可以在登机之前检查票证并完全消除对票务服务的依赖。好吧,这是另一个主题。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么函数中本地定义的结构需要赋值运算符和复制构造函数

来自分类Dev

为什么std :: make_shared需要默认构造函数?

来自分类Dev

嵌套的构造函数。为什么需要它?

来自分类Dev

为什么在const成员struct中需要构造函数?

来自分类Dev

为什么View构造函数需要Context对象

来自分类Dev

为什么我们需要在MSIL中显式调用父构造函数?

来自分类Dev

Singleton实现-为什么需要复制构造函数?

来自分类Dev

为什么在OOP中需要构造函数?

来自分类Dev

为什么javascript函数原型需要修复构造函数?

来自分类Dev

为什么需要复制构造函数,何时在Java中使用复制构造函数

来自分类Dev

为什么需要复制构造函数,何时在Java中使用复制构造函数

来自分类Dev

为什么std :: vector的元素需要移动构造函数?

来自分类Dev

为什么赋值初始化如果不使用它就需要复制构造函数

来自分类Dev

为什么在Atomic {Type} Array构造函数中需要volatileWrite

来自分类Dev

为什么noexcept构造函数需要实例化析构函数?

来自分类Dev

为什么需要使用多个构造函数?

来自分类Dev

为什么Promise构造函数需要执行程序?

来自分类Dev

为什么需要在构造函数中绑定函数

来自分类Dev

为什么移动构造函数的成员需要默认构造函数?

来自分类Dev

C ++:没有匹配的调用函数:为什么需要一个空的构造函数?

来自分类Dev

为什么在具有主构造函数的记录中需要显式的“ this”构造函数初始化器?

来自分类Dev

为什么类需要默认构造函数,而结构却不需要?

来自分类Dev

嵌套的构造函数。为什么需要它?

来自分类Dev

为什么构造函数需要在类的后面精确命名?

来自分类Dev

为什么std :: vector的元素需要移动构造函数?

来自分类Dev

为什么在Atomic {Type} Array构造函数中需要volatileWrite

来自分类Dev

为什么需要使用多个构造函数?

来自分类Dev

为什么复制构造函数需要为const?

来自分类Dev

为什么需要在构造函数中调用超类?

Related 相关文章

  1. 1

    为什么函数中本地定义的结构需要赋值运算符和复制构造函数

  2. 2

    为什么std :: make_shared需要默认构造函数?

  3. 3

    嵌套的构造函数。为什么需要它?

  4. 4

    为什么在const成员struct中需要构造函数?

  5. 5

    为什么View构造函数需要Context对象

  6. 6

    为什么我们需要在MSIL中显式调用父构造函数?

  7. 7

    Singleton实现-为什么需要复制构造函数?

  8. 8

    为什么在OOP中需要构造函数?

  9. 9

    为什么javascript函数原型需要修复构造函数?

  10. 10

    为什么需要复制构造函数,何时在Java中使用复制构造函数

  11. 11

    为什么需要复制构造函数,何时在Java中使用复制构造函数

  12. 12

    为什么std :: vector的元素需要移动构造函数?

  13. 13

    为什么赋值初始化如果不使用它就需要复制构造函数

  14. 14

    为什么在Atomic {Type} Array构造函数中需要volatileWrite

  15. 15

    为什么noexcept构造函数需要实例化析构函数?

  16. 16

    为什么需要使用多个构造函数?

  17. 17

    为什么Promise构造函数需要执行程序?

  18. 18

    为什么需要在构造函数中绑定函数

  19. 19

    为什么移动构造函数的成员需要默认构造函数?

  20. 20

    C ++:没有匹配的调用函数:为什么需要一个空的构造函数?

  21. 21

    为什么在具有主构造函数的记录中需要显式的“ this”构造函数初始化器?

  22. 22

    为什么类需要默认构造函数,而结构却不需要?

  23. 23

    嵌套的构造函数。为什么需要它?

  24. 24

    为什么构造函数需要在类的后面精确命名?

  25. 25

    为什么std :: vector的元素需要移动构造函数?

  26. 26

    为什么在Atomic {Type} Array构造函数中需要volatileWrite

  27. 27

    为什么需要使用多个构造函数?

  28. 28

    为什么复制构造函数需要为const?

  29. 29

    为什么需要在构造函数中调用超类?

热门标签

归档