PHP 控制反转(IOC) 和 依赖注入(DI)

71 阅读1分钟

控制反转(IOC)是一种思想,依赖注入(DI)是实施这种思想的方法。

简单实现一个代码依赖:

<?php

class iocA
{
    public $b;
    public $c;

    public function A()
    {
        //TODO
    }

    public function Method()
    {
        $this->b = new iocB();
        $this->c = new iocC();

        $this->b->Method();
        $this->c->Method();
    }
}

class iocB
{
    public function C()
    {
        //TODO
    }

    public function Method()
    {
        echo 'b';
    }
}

class iocC
{
    public function C()
    {
        //TODO
    }

    public function Method()
    {
        //TODO
        echo 'c';
    }
}

$a = new iocA();
$a->Method();

上边的代码实现了 A 类依赖 B 类和 C 类。

如果在开发过程中,需要对 B 类或者 C 类进行修改,,一旦涉及到函数名称的改变,或者函数参数数量的变动,或者整个类结构的变化,我们也需要对 A 类进行调整,A 类的独立性就丧失了,这在开发中和不方便,代码复杂,耦合度不尽人意,这样会造成“牵一发动全身”,解决这个问题就需要用到 控制翻转(IOC)。

依赖注入的实现

第一种:构造器注入

<?php

class iocA
{
    public $b;
    public $c;

    public function __construct($iocB, $iocC)
    {
        $this->b = $iocB;
        $this->c = $iocC;
    }

    public function Method()
    {
        $this->b->Method();
        $this->c->Method();
    }
}

class iocB
{
    public function C()
    {
        //TODO
    }

    public function Method()
    {
        echo 'b';
    }
}

class iocC
{
    public function C()
    {
        //TODO
    }

    public function Method()
    {
        //TODO
        echo 'c';
    }
}

$a = new iocA(new iocB(), new iocC());
$a->Method();

A类的构造器依赖B类和C类,通过构造器的参数传入,至少实现了一点,就是B类对象b和C类对象c的创建都移至了A类外,所以一旦B类和C类发生改动,A类无需做修改,只要在client类里改就可以了。

第二种:工厂模式注入

<?php

class Factory
{
    public function Factory()
    {
        //TODO
    }

    public function create($s)
    {
        switch ($s) {
            case 'B':
            {
                return new iocB();
                break;
            }
            case 'C':
            {
                return new iocC();
                break;
            }
            default:
            {
                return null;
                break;
            }
        }
    }
}

class iocA
{
    public $b;
    public $c;

    public function __construct()
    {
        //TODO
    }

    public function Method()
    {
        $factory = new Factory();
        $this->b = $factory->create('B');
        $this->c = $factory->create('C');

        $this->b->Method();
        $this->c->Method();
    }
}

class iocB
{
    public function C()
    {
        //TODO
    }

    public function Method()
    {
        echo 'b';
    }
}

class iocC
{
    public function C()
    {
        //TODO
    }

    public function Method()
    {
        //TODO
        echo 'c';
    }
}

$a = new iocA();
$a->Method();

其实已经解耦了一小部分,至少如果B类和C类的构造函数要是发生变化,比如修改函数参数等,我们只需要改Factory类就可以了。

抽象不应该依赖于细节,细节应该依赖于抽象。