極簡架構模式-依賴注入模式

long2ge發表於2021-12-17

定義

依賴注入是指不是由內部生產(初始化、建構函式 __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的服務容器
本作品採用《CC 協議》,轉載必須註明作者和本文連結
Long2Ge

相關文章