簡析IoC控制反轉

簡析IoC控制反轉

設計模式原則

  1. 開閉原則:開放擴展,關閉修改。主要將的就是抽象化
  2. 里氏代換替換原則:任何基類能夠出現的地方,子類必定能夠出現。
  3. 依賴倒轉原則:儘可能依賴抽象接口編程而不要去依賴具體實例。🌟
  4. 接口隔離原則:使用多個隔離的接口要好過單個接口。
  5. 迪米特原則:一個實例儘可能少知道與其餘實例之間的相互做用關係,使功能模塊相對獨立。
  6. 合成複用原則:儘可能使用聚合和組合,少用依賴。🌟

什麼是IoC

控制反轉(簡稱IoC),是一種面向對象的設計思想,用來下降代碼間的耦合度。經過控制反轉,對象在被建立的時候,由一個調控系統內全部對象的外界實體,將其所依賴的對象的引用傳遞給它。也就是將依賴被注入到要調用的對象中。控制反轉通常和容器思想結合使用,Ioc就是將對象交給容器去控制,而不是在對象內部直接控制,主要是控制對象的內部依賴。

php

  • 誰控制誰

IoC經過一個專門的容器來建立對象,經過IoC容器來控制對象laravel

  • 控制什麼

控制實例的外部依賴編程

  • 關於反轉設計模式

    • 正轉:由對象去主動獲取本身須要的依賴,並控制依賴叫正轉
    • 反轉:由new對象的容器去獲取並建立依賴,對象被動接受依賴,從而組合成一個具備具體功能的實例。



IoC的做用

IoC是一種面向對象的變成思想和指導準則。解決傳統控制正轉開發中在類內部主動建立依賴類,從而致使類的內部耦合,難以複用。IoC把查找建立依賴的控制權反轉給容器,由容器進行注入來組合建立一個對象,不一樣需求容器能夠注入不一樣的對象,從而消除對象和依賴的耦合。數組

IoC思想的實現

DI依賴注入

依賴注入指容器在運行中動態的將依賴注入到組件中,從而使組件具備具體的功能。經過依賴注入能夠在特殊的地方指定同一個抽象方法去處理不一樣依賴對象的邏輯,而不須要了解和修改具體抽象方法的實現,只須要關注本身的業務層。框架

  • 誰依賴誰

實例化類依賴控制容器函數

  • 爲何要依賴

實例化類須要依賴其餘資源才能夠處理具體業務this

  • 誰注入誰

IoC容器向實例化類中注入了某個依賴spa

  • 注入了什麼

實例化類須要處理的依賴對象
設計

如何實現

  • 基於構造函數。實現特定參數的構造函數,在新建對象時傳入所依賴類型的對象。
  • 基於接口。實現特定接口以供外部容器注入所依賴類型的對象。
  • 基於 set 方法。實現特定屬性的 public set 方法,來讓外部容器調用傳入所依賴類型的對象。
interface Way
{
    public function go();
}

class GoShanghai
{
    private $charger;

    public function __construct(Way $charger)
    {
        $this->charger = $charger;
    }

        public function setWay(Way $way)
    {
        $this->way = $way;
    }

    public function go()
    {
        $this->charger->go();
    }

}

class Car implements Way
{
    public function go()
    {
        // TODO: Implement go() method.
        print_r("我經過開車去上海");
    }
}
// 基於構造函數和接口
$goshanghai = new GoShanghai(new Car());
$goshanghai->go();
// 基於set方法|展現須要由於構造函數運行會出錯
$goshanghai = new GoShanghai();
$goshanghai->setWay(new Car());
$goshanghai->go();

依賴查找

依賴查找更加主動,在須要的時候經過調用框架提供的方法來獲取對象,獲取時須要提供相關的配置文件路徑、key等信息來肯定獲取對象的狀態。

實現IoC的設計模式

OP觀察者模式

觀察者模式主要用於處理對象直接一對多多關係。當外部資源發生改變,觀察者會獲得通知。觀察者和被觀察者直接是抽象耦合的,也就不影響實例的解藕。

  • 什麼是觀察者

觀察者是一對多關係中的多,觀察者須要根據目標對象改變而改變的對象。

  • 觀察什麼

觀察目標對象的某些特定的狀態。

  • 如何觀察

觀察者繼承自一個抽象觀察類,抽象觀察類實現註冊、監聽和通知功能。

如何實現

observer_pattern_uml_diagram.jpg

/**
 * 觀察者的抽象類
 */
abstract class Observer
{
    // 這是一個目標類
    protected $subject;

    // 定義一個用於更新的抽象方法
    public abstract function update();
}

/**
 * 目標類
 */
class Subject {

    // 觀察者數組集合
    private $observerList = array();

    // 狀態,這裏遵循開閉原則將屬性私有化
    private $state = 0;

    /**
     * 獲取狀態的值
     */
    public function getState() :int
    {
        return $this->state;
    }

    /**
     * 設置狀態的值
     * @param int $state
     */
    public function setState(int $state)
    {
        $this->state = $state;
        $this->notifyAllObservers();
    }

    /**
     * 註冊觀察者
     * @param Observer $observer
     */
    public function attach(Observer $observer)
    {
        array_push($this->observerList, $observer);
    }

    /**
     * 通知觀察者
     */
    public function notifyAllObservers()
    {
        foreach ($this->observerList as $observer) {
            $observer->update();
        }
    }
}

/**
 * 觀察者A
 */
class AObserver extends Observer
{
    public function __construct(Subject $subject)
    {
        // 注入目標依賴實現IoC
        $this->subject = $subject;

        // 註冊觀察者
        $this->subject->attach($this);
    }

    public function update()
    {
        // TODO: Implement update() method.
        print_r("A觀察者更新了支付業務的狀態:{$this->subject->getState()}\n");
    }
}
// 建立一個目標對象
$subject = new Subject();

// 爲目標對象綁定觀察者
new AObserver($subject);

print_r("目標對象的狀態:{$subject->getState()}\n");
$subject->setState(10);

// 目標對象的狀態:0
// A觀察者更新了支付業務的狀態:10

TP模版模式

經過一個抽象基類定義執行它的模版也能夠是方法,子類重寫抽象方法的實現,但調用實在抽象基類中完成的,從而實現控制反轉。就是基類控制行爲,子類完成實現。

如何實現

template_pattern_uml_diagram.jpg

/**
 * 抽象模版類
 */
abstract class Template
{
    // 抽象方法A
    public abstract function stepA();

    // 抽象方法B
    public abstract function stepB();

    // 執行定義的步驟, 這裏使用了final關鍵字修飾,final的做用是使這個方法不可被繼承, 這樣就不會被子類執行
    public final function run()
    {
        $this->stepA();
        $this->stepB();
    }
}

/**
 * 方案A的實例
 */
class FuncA extends Template
{
    public function stepA()
    {
        // TODO: Implement stepA() method.
        print_r("方案A第一步\n");
    }

    public function stepB()
    {
        // TODO: Implement stepB() method.
        print_r("方案A第二步\n");
    }
}
$funca = new FuncA();
$funca->run();

Laravel中的IoC

上面的例子能夠看到控制反轉使每一個業務實例相對對立,他們的組裝在代碼執行時完成,當業務簡單、依賴單一時看上去沒有問題,可是當依賴複雜時會致使組裝變得繁瑣且難以梳理。在laravel中是經過容器Container來解決這個問題。下面咱們經過幾句話來簡單看一下laravel中容器的使用。

  • 啓動laravel時就是啓動了一個容器
  • 容器內的實例在一次應用程序級調用中是單例的
  • 經過make實現自動序列化依賴對象,代替new
  • 經過bind方法讓每個抽象接口和它的實例類一一對應
  • 經過resolveing方法註冊一個回調callback在綁定的對象解析完以後調用
相關文章
相關標籤/搜索