理解依賴注入和控制反轉

1.控制反轉(Inversion of Control,縮寫爲IoC)

是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用傳遞(注入)給它。

2.DIP - 依賴倒置原則

依賴倒置(Dependence Inversion Principle,簡稱DIP,是一種抽象的軟件設計原則,它主要是告訴我們一些規範我們先看下官方對於這個原則的定義

高層模塊不應依賴於低層模塊,兩者應該依賴於抽象。

抽象不應該依賴於實現,實現應該依賴於抽象。

具體是什麼意思呢我們可以通過一個例子來說明下這個原則,大家應該都對電腦上的 USB 插口很熟悉,通過它我們可以擴展各種的外設能力,例如 U盤、遊戲鼠標等等,只要接口一致,插上設備就能正常工作。

在這個例子中,我們的電腦就相當於是高層模塊,而 U盤、鼠標等就相當於是底層模塊。我們的電腦定義了一個插口(接口),可以供其他的設備插入使用,但是我們的電腦並不依賴於具體要插入的設備,它只是定義好了一個接口規範,只要是符合這個接口規範的設備都可以插入到這臺電腦上來使用。那麼對應到軟件開發上來看指的就是 依賴倒置原則轉換了依賴關係,要求高層的模塊不應該依賴於底層模塊的實現,底層的模塊要依賴於高層模塊定義的接口

上面的例子只是說清楚了 依賴倒置原則(DIP) 的規範定義,下面我們再通過一個軟件開發的場景例子看看爲何需要設計這個原則。

場景:比如我們有一個業務需要對數據做入庫操作,目標可能是 MySql、MongoDb 等。

實現一:無依賴倒置,即底層定義接口,高層模塊實現。

在不實用依賴倒置的情況下,我們要完成此場景的功能非常的麻煩,我們的業務類(高層模塊)要實現所有的 DB類(底層模塊) 接口,如果再有新的 DB類(底層模塊)介入,則又需要去修改業務類(高層模塊)來實現新的 DB類(底層模塊)這就破壞了類的開放封閉原則。

實現二:使用依賴倒置,即高層定義接口,底層模塊實現。

我們使用依賴倒置後,我們的業務類(高層模塊)將不再依賴 DB類(底層模塊)而是由 DB類(底層模塊)負責實現業務類(高層模塊)的接口,這樣即使由新的底層模塊加入到業務中時我們也不需要修改業務模塊。

由此可見使用 DIP 的好處:

  • 可以通過抽象使各個類或模塊的實現彼此獨立,不互相影響,實現模塊間的鬆耦合(也是本質);

  • 可以規避一些非技術因素引起的問題(如項目大時,需求變化的概率也越大,通過採用依賴倒置原則設計的接口或抽象類對實現類進行約束,可以減少需求變化引起的工作量劇增情況。同時,發生人員變動,只要文檔完善,也可讓維護人員輕鬆地擴展和維護);

可以促進並行開發(如,兩個類之間有依賴關係,只要制定出兩者之間的接口(或抽象類)就可以獨立開發了,而且項目之間的單元測試也可以獨立地運行,而TDD開發模式更是DIP的最高級應用(特別適合項目人員整體水平較低時使用))

DIP-依賴倒置原則,但是它只是一種 軟件設計原則 它僅僅是爲我們提供一個標準,以便我們可以遵循,避免不良的設計,但是它並不會告訴我們這些標準如何實現。 IOC 是一種 軟件設計模式 即它爲我們如何實現 DIP 提供了詳細的解決方案。

MysqlDb.class.php

<?php
require_once('./DbDrive.php');

/**
 * Class MysqlDb
 *
 * @since 2.0
 */
class MysqlDb implements DbDrive
{
    public function insert()
    {
        //TODO::插入一些數據
        echo '用到了MysqlDb';
    }

    public function update(){}
}

MongoDb.class.php

<?php
require_once('./DbDrive.php');

/**
 * Class MongoDb
 *
 * @since 2.0
 */
class MongoDb implements DbDrive
{
    public function insert()
    {
        //TODO::插入一些數據
        echo '用到了MongoDb';
    }

    public function update(){}
}

DbDrive.php

<?php
/**
 * Interface DbDrive
 *
 * @since 2.0
 */
interface DbDrive
{
    public function insert();

    public function update();
}

Order.php

<?php
require_once('./DbDrive.php');
/**
 * Class Order
 *
 * @since 2.0
 */
class Order
{
    /**
     * @var DbDrive
     */
    private $db;

    /**
     * Order constructor.
     *
     * @param DbDrive $driver
     */
    public function __construct(DbDrive $driver)
    {
        $this->db = $driver;
    }

    public function add()
    {
        //TODO::訂單業務
        $this->db->insert();//執行入庫操作
    }
}

addOrder.php

<?php
require_once('./Order.php');
require_once('./MysqlDb.class.php');
require_once('./MongoDb.class.php');
require_once('./Container.php');

$db = new MysqlDb();//創建一個依賴
$db = new MongoDb();//創建一個依賴
$order = new Order($db);//將需要依賴的對象通過構造函數傳遞進去
$order->add();//正常的去調用業務。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章