依賴倒置原則 DIP(Dependence Inversion Principle)

依賴倒置原則 DIP(Dependence Inversion Principle)html

控制反轉(Inversion of Control, IoC) IoC就是DIP的一種具體思路,DIP只是一種理念、思想,而IoC是一種實現DIP的方法。 IoC的核心是將類(上層)所依賴的單元(下層)的實例化過程交由第三方來實現。 一個簡單的特徵,就是類中不對所依賴的單元有諸如 $component = new yii\component\SomeClass() 的實例化語句。 . 依賴注入(Dependence Injection, DI) DI是IoC的一種設計模式,是一種套路,按照DI的套路,就能夠實現IoC,就能符合DIP原則。 DI的核心是把類所依賴的單元的實例化過程,放到類的外面去實現。設計模式

控制反轉容器(IoC Container) 當項目比較大時,依賴關係可能會很複雜。 而IoC Container提供了動態地建立、注入依賴單元,映射依賴關係等功能,減小了許多代碼量。yii

服務定位器(Service Locator) Service Locator是IoC的另外一種實現方式, 其核心是把全部可能用到的依賴單元交由Service Locator進行實例化和建立、配置, 把類對依賴單元的依賴,轉換成類對Service Locator的依賴。 DI 與 Service Locator並不衝突,二者能夠結合使用。函數

依賴注入測試

場景:假設要實現當訪客在博客上發表評論後,向博文的做者發送Email的功能,一般代碼會是這樣:

//爲郵件服務定義抽象層
interface IEmailSender{
	public function send(...$param);
	...
}

//定義Gmail郵件服務
class GmailSender implements IEmailSender{
	public function send(...$param){
		...
	}
	...
}

//定義評論類
class Comment extends CommentDB{
	//用於引用發送郵件的庫
	private $_eMailSender;

	//初始化時,實例化$eMailSender
	public function init(){
		//這裏假設使用Gmail郵件服務
		$this->_eMailSender = new GmailSender();
	}

	//當有新評論,即save()方法被調用以後中,會觸發該方法
	public function afterInsert(){
		$this->_eMailSender->send(...$param);
		...
	}
}

試想若是如今咱們不想使用Gmail郵件服務了,咱們改用阿里雲的或者本身的郵件服務,那麼,你不得不修改 Comment::init() 裏面對 $_eMailSender 的實例化語句:$this->_eMailSender = new GmailSender(); 不但違反了OO思想的開閉原則並且對於複用性、維護性、測試、擴展都帶來了不便,不是不便並且很是不方便。 依賴注入就是爲了解決這個問題而生的,固然,DI也不是惟一解決問題的辦法,畢竟條條大路通羅馬。 Service Locator也是能夠實現解耦的。this

//構造函數注入、屬性輸入
class Comment extends IComment{
	private $_eMailSender;

	public function __construct($eMailSender){
		$this->_eMailSender = $eMailSender;
	}

	//當有新評論,即save()方法被調用以後中,會觸發該方法
	public function afterInsert(){
		$this->_eMailSender->send(...$param);
		...
	}
}

//實例化兩種不一樣的郵件服務,固然,他們都實現了EmailSenderInterface
$sender1 = new GmailSender();
$sender2 = new MyEmailSender();

//用構造函數將GamilSender注入
$comment1 = new Comment($sender1);
//使用Gmail發送郵件
$comment1->save();

//用構造函數將MyEmailSender注入
$comment2 = new Comment($sender2);
//使用MyEmailSender發送郵件
$comment2->save();

上面代碼對比原來代碼,解決了Comment類對於Gmail等具體類的依賴,將死的代碼成活的的了(專業術語爲:編譯時轉爲運行時)。這種思想充分的展現了擴展性須要什麼郵件服務類寫出新的類便可、靈活性編譯時轉爲運行時、複用性不論什麼項目只要用到了郵件模塊就可使用,郵件模塊具備獨立性。阿里雲

依賴注入容器設計

從上面DI兩種注入方式來看,依賴單元的實例化代碼是一個重複、繁瑣的過程。 能夠想像,一個Web應用的某一組件會依賴於若干單元,這些單元又有可能依賴於更低層級的單元, 從而造成依賴嵌套的情形。code

參考文獻:component

依賴注入和依賴注入容器

相關文章
相關標籤/搜索