OOD、DIP、IOC、DI、依賴注入容器(即 控制反轉容器,IOC Container)

灰色v碰觸發表於2019-02-16

1. 名詞介紹

  1. OOD,物件導向設計

  2. DIP,依賴倒置(軟體設計原則)

  3. IOC,控制反轉(軟體設計模式)

  4. DI,依賴注入

  5. IOC Container,控制反轉容器,也是依賴注入容器

2. 組成部分

  1. 服務清單(功能清單,service list)

  2. 服務(高層類,service ,對外提供服務)

  3. 服務提供者(底層類,service provider ,實際提供服務的物件)

2. 依賴倒置原則(DIP)

2.0 介紹

依賴倒置原則,它轉換了依賴,高層模組不依賴於低層模組的實現,而低層模組依賴於高層模組定義的介面

詳細介紹請點我

2.1 場景描述

提供一個計算機儲存的服務。需要根據不同的使用者需求,使用不同的儲存裝置。

2.2 沒有遵循依賴倒置原則的例子

2.2.1 定義好服務提供者(實際提供服務)

// 定義一個 硬碟儲存類 (服務提供者)
class HardDiskStorage {
    public function saveToHardDisk(){
        
    }
    
    public function readFromHardDisk(){
        
    }
}

// 定義一個 U盤儲存類(服務提供者)
class UStorage {
    public function saveToU(){
        
    }
    
    public function readFromU(){
        
    }
}

2.2.2 定義 服務(對外提供服務的物件)

/**
 * 定義一個 ComputerStorage 類(儲存服務)
 */ 

// 第一種:使用硬碟作為提供實際服務的物件
class ComputerStorage {
    protected $_storage = null;
    
    function __construct(){
        $this->_storage = new HardDiskStorage();
    }
    
    public function save(){
        $this->_storage->saveToHardDisk();
    }
    
    public function read(){
        $this->_storage->readFromHardDisk();
    }
}

// 第二種:使用 U 盤作為提供實際服務的物件
class ComputerStorage {
    protected $_storage = null;
    
    function __construct(){
        $this->_storage = new UStorage();
    }
    
    public function save(){
        $this->_storage->saveToU();
    }
    
    public function read(){
        $this->_storage->readFromU();
    }
}

// 讀取
$cs = new ComputerStorage();
$cs->read();

2.2.3 程式碼分析

根據上面的程式碼,當切換服務提供者時,服務類的程式碼需要做較多的改動。服務(ComputerStorage)本省作為一個高層類,對外提供訪問,卻受制於提供具體服務的服務提供者(HardDiskStorageUStorage)定義的實現(saveToHardDisksaveToUreadFromHardDiskreadFromU),高層模組依賴底層模組實現,違背了依賴倒置原則。

2.3 遵循依賴倒置原則的例子

2.3.1 場景

2.1 介紹中場景。

2.3.2 定義服務清單(高層模組定義介面)

interface ServiceList {
    public function save();
    public function read();
}

2.3.3 定義服務提供者

// 硬碟
class HardDiskStorage implements ServiceList {
    public function save(){
        
    }
    
    public function read(){
        
    }
}

// U 盤
class UStorage implements ServiceList {
    public function save(){
        
    }
    
    public function read(){
        
    }
}

2.3.4 定義服務

class ComputerStorage {
    protected $_storage = null;
    
    function __construct(){
        $this->_storage = new HardDiskStorage();        
    }
    
    public function save(){
        $this->_storage->save();
    }
    
    public function read(){
        $this->_storage->read();
    }
}

$cs = new ComputerStorage();
$cs->read();

2.3.5 程式碼分析

上述程式碼中,事先定義了好了服務清單(介面,ServiceList),然後服務提供者實現這些介面(HardDiskStorageUStorage),服務(ComputerStorage)只需要切換服務提供者即可(HardDiskStorageUStorage),完全無需理會他們的實現(readFromHardDiskreadFromU…等)。高層模組不依賴於底層模組定義的實現,遵循了依賴倒置原則

3. 控制反轉(IOC) + 依賴注入(DI)

3.0 介紹

控制反轉(IoC),它為相互依賴的元件提供抽象,將依賴(低層模組)物件的獲得交給第三方(系統)來控制,即依賴物件不在被依賴模組的類中直接通過new來獲取

詳細介紹請點我

3.1 場景

2 場景

3.2 沒有實現控制反轉的例子

2 中的例子就是沒有實現控制反轉的例子。2ComputerStorage 獲取依賴(HardDiskStorageUStorage)的途徑都是在 contruct 建構函式中獲取的,即 類內部例項化依賴獲取。

3.3 實現控制反轉的例子

以下程式碼是根據 2 中的程式碼做了些許的調整。

class ComputerStorage {
    protected $_storage = null;
    
    /**
     * 內部只獲取依賴的例項
     */
    public function setStorage($storage){
        $this->_storage = $storage;
    }

    public function save(){
        $this->_storage->save();
    }
    
    public function read(){
        $this->_storage->read();
    }
}

// 外部例項化依賴
$hardDiskStorage = new HardDiskStorage();

$cs = new ComputerStorage();
// 注入依賴
$cs->setStorage($hardDiskStorage);

4. 依賴注入容器(IOC 容器)

4.0 場景

2 場景。

4.1 使用 IOC容器

class Container {
    // 登錄檔
    protected static $_registry = null;
    
    // 儲存到登錄檔
    public static function set($classname , Callable $create){
        self::$_registry[$classname] = $create;
    }
    
    // 獲取登錄檔對應類的例項
    public static function get($key){
        call_user_func(self::$_registry[$key]);
    }
}

class ComputerStorage {
    protected $_storage = null;
    
    function __construct(){
        $this->_storage = Container::get(`HardDiskStorage`);
    }
    
    public function read(){
        $this->_storage->read();
    }
    
    public function save(){
        $this->_storage->save();
    }
}

/**
 * 註冊依賴
 */
Container::set(`HardDiskStorage` , function(){
    return new HardDiskStorage();
});

Container::set(`UStorage` , function(){
    return new UStorage();
});

// 測試
$cs = new ComputerStorage();

$cs->read();

相關文章