先看一個範例:
<?php class A { public $b; public $c; public function A() { //TODO } public function Method() { $this->b=new B(); $this->c=new C(); $this->b->Method(); $this->c->Method(); //TODO } } class B { public function B() { //TODO } public function Method() { //TODO echo 'b'; } } class C { public function C() { //TODO } public function Method() { //TODO echo 'c'; } } $a=new A(); $a->Method(); ?>
上面程式碼,我們很容易理解一句話:
##A類別依賴B類別與C類別
也就是說,如果今後開發過程中,要對B類別或C類別修改,一旦涉及函數改名,函數參數數量變動,甚至整個類別結構的調整,我們也要對A類做出相對應的調整,A類的獨立性喪失了,這在開發過程中是很不方便的,也就是我們說的“牽一發動全身”,如果兩個類是兩個人分別寫的,矛盾往往就在這個時候產生了。 。 。
萬一真的要改動B類和C類,有沒有辦法,可以不去改動或盡量少改動A類的程式碼呢?這裡要用到控制反轉。高層模組不應該依賴底層模組,兩個都應該依賴抽象。控制反轉(IOC)是一種思想,
依賴注入(DI)是實施這種思想的方法。
第一種方法叫做:建構器注入(這種方法也不建議用,但比不用好)class A { public $b; public $c; public function A($b,$c) { $this->b=$b; $this->c=$c; } public function Method() { $this->b->Method(); $this->c->Method(); } }客戶端類別這樣寫:
$a=new A(new B(),new C()); $a->Method();A類別的建構器依賴B類和C類,透過建構器的參數傳入,至少實現了一點,就是B類
物件b和C類別物件c的建立都移至了A類別外,所以一旦B類別和C類別發生改動,A類別無需做修改,只要在client類別裡改就可以了
假如有一天,我們需要擴充B類,做兩個B類的子類class B { public function B() { //TODO } public function Method() { //TODO echo 'b'; } } class B1 extends B { public function B1() { //TODO } public function Method() { echo 'b1'; } } class B2 extends B { public function B2() { //TODO } public function Method() { echo 'b2'; } }也很簡單,客戶端類別這麼寫:
$a=new A(new B2(),new C()); $a->Method();所以A類別是不用關心B類別到底有哪些個子類別的,只要在客戶端類別關心就好了。 第二種方法叫做:
工廠模式注入(建議使用)
#
class Factory { public function Factory() { //TODO } public function create($s) { switch($s) { case 'B': { return new B(); break; } case 'C': { return new C(); break; } default: { return null; break; } } } }我們A類別程式碼改為:
class A { public $b; public $c; public function A() { //TODO } public function Method() { $f=new Factory(); $this->b=$f->create('B'); $this->c=$f->create('C'); $this->b->Method(); $this->c->Method(); //TODO } }其實已經解耦了一小部分,至少如果B類和C類的
建構子要是變化,例如修改函數參數等,我們只需要改Factory類別就可以了。
抽像不應該依賴細節,細節應該依賴抽象。把B類別和C類別中的方法再抽像出來,做一個
#
interface IMethod { public function Method(); }這樣,A類別中的$b
變數和$c變數就不再是一個具體的變數了,而是一個抽象類別型的變量,不到執行那一刻,不知道他們的Method方式是怎麼實現的。
class B implements IMethod { public function B() { //TODO } public function Method() { //TODO echo 'b'; } } class C implements IMethod { public function C() { //TODO } public function Method() { //TODO echo 'c'; } }總結幾點:1.我們把A類別中的B類別物件和C類別物件的建立移至A類別外2.原本A類依賴B類和C類,現在變成了A依賴Factory,Factory依賴B和C。
以上是PHP控制反轉(IOC)和依賴注入(DI)的實例程式碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!