极简架构模式-依赖注入模式

PHP技术
473
0
0
2022-08-07

依赖注入 - Dependence Inversion - DI

定义

依赖注入是指不是由内部生产(初始化、构造函数 __construct 中通过工厂方法、自行手动 new 的),而是由外部以参数或其他形式注入的。

解释

简单来说就是把依赖对象的实例化过程交给第三方(IOC容器)来实现。

控制 : 依赖对象实例化的控制。

正向 : 我们在对象中主动获取依赖对象。

反向 : IOC容器生成依赖对象,并且把依赖对象传递到资源对象中。资源对象获取依赖对象的方式反转了,由主动创建变成被动接受了。

IOC容器 : 一个类,它负责控制所有对象的生命周期和各个对象之间的关系。

结构中包含的角色

  1. IocContainer (IOC容器)
  2. AbstractResource (抽象资源))
  3. Resource (具体资源)
  4. AbstractResourceDependent (抽象资源依赖)
  5. ResourceDependent (资源依赖)

最小可表达代码

class ResourceDependent {}

class Resource 
{
    private $resourceDependent;

    public function __construct(ResourceDependent $resourceDependent)
    {
        $this->resourceDependent = $resourceDependent;
    }
}

// 依赖注入
$resource = new Resource(new ResourceDependent);

简化版Laravel服务容器代码

abstract class AbstractResourceDependent {}

class ResourceDependent extends AbstractResourceDependent {}

abstract class AbstractResource
{
    private $resourceDependent;

    public function __construct(AbstractResourceDependent $resourceDependent)
    {
        $this->resourceDependent = $resourceDependent;
    }

    public function debug()
    {
        return 'test';
    }
}

class Resource extends AbstractResource {}

class IocContainer 
{
    // 绑定的数据   
    protected $bindings = [];

    // 实例化的数据   
    protected $instances = [];

    // 绑定数据   
    public function bind($abstract, $concrete = null)
    {
        // 包装成闭包   
        if (! $concrete instanceof Closure) {
            $concrete = $this->getClosure($abstract, $concrete);
        }

        $this->bindings[$abstract] = compact('concrete');
    }

    // 包装成闭包的方法   
    protected function getClosure($abstract, $concrete)
    {
        return function ($container) use ($abstract, $concrete) {
            if ($abstract == $concrete) {
                return $container->build($concrete);
            }

            return $container->make($concrete);
        };
    }

    // 解析数据   
    public function make($abstract)
    {
        // 已经有,直接返回   
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        // 获取绑定的数据   
        $concrete = $this->getConcrete($abstract);

        $object = $this->build($concrete);

        return $object;
    }

    // 创建数据   
    public function build($concrete)
    {
        if ($concrete instanceof Closure) {
            return $concrete($this);
        }

        // 暂时屏蔽反射生成的逻辑   
        // $reflector = new ReflectionClass($concrete);   
        return new $concrete;
    }

    // 获取绑定的数据   
    protected function getConcrete($abstract)
    {
        if (isset($this->bindings[$abstract])) {
            return $this->bindings[$abstract]['concrete'];
        }

        return $abstract;
    }
}

$app = new IocContainer;

$app->bind(AbstractResourceDependent::class, function ($app) {
    return new ResourceDependent();
});

$app->bind(AbstractResource::class, function ($app) {
    return new Resource($app->make(AbstractResourceDependent::class));
});

$resource = $app->make(AbstractResource::class);

var_dump($resource->debug());

实际应用场景

  1. Laravel的服务容器
  2. Spring的服务容器