這次給大家帶來PHP介面隔離原則(ISP)使用案例解析,PHP介面隔離原則(ISP)使用的注意事項有哪些,下面就是實戰案例,一起來看一下。
設計應用程式的時候,如果一個模組包含多個子模組,那麼我們應該小心對模組做出抽象。設想該模組由一個類實現,我們可以把系統抽象成一個介面。但是要添加一個新的模組擴充程式時,如果要添加的模組只包含原系統中的一些子模組,那麼系統就會強迫我們實現介面中的所有方法,並且清寒要編寫一些啞方法。這樣的介面被稱為肚胖介面或者被汙染的介面,使用這樣的介面將會給系統引入一些不當的行為,這些不當的行為可能導致不正確的結果,也可能匯入資源浪費。
1.介面隔離
介面隔離原則(Interface Segregation Principle, ISP)表明用戶端不應該被強迫實現一些他們不會使用的介面,應該把胖介面中的方法分組,然後用多個介面替代它,每個介面服務於一個子模組。簡單地說,就是使用多個專門的介面比使用單個介面要好很多。
ISP的主要觀點如下:
1)一個類對另外一個類的依賴性應當是建立在最小的介面上的。
ISP可以達到不強迫客戶(介面的使用方法)依賴於他們不用的方法,介面的實作類別應該只呈現為單一職責的角色(遵循SRP原則)
ISP還可以降低客戶之間的相互影響---當某個客戶要求提供新的職責(需要變化)而迫使介面發生改變時,影響到其他客戶程式的可能性最小。
2)用戶端程式不應該依賴它不需要的介面方法(功能)。
用戶端程式就應該依賴於它不需要的介面方法(功能),那依賴於什嗎?依賴它所需要的介面。用戶端需要什麼介面就是提供什麼介面,把不需要的介面剔除,這就要求對介面進行細化,保證其純潔性。
比如在繼承時,由於子類將繼承父類中的所有可用方法;而父類中的某些方法,在子類中可能並不需要。例如,普通員工和經理都繼承自僱員這個介面,員工需要每天寫工作日誌,而經理不需要。因此不能用工作日誌來卡經理,也就是經理不應該依賴於提交工作日誌這個方法。
可以看出,ISP和SRP在概念上是有一定交叉的。事實上,很多設計模式在概念上都有交叉,甚至你很難判斷一段代碼屬於哪一種設計模式。
ISP強調的是介面對用戶端的承諾越少越好,並且要做到專一。當某個客戶程式的要求發生變化,而迫使介面發生改變時,影響到其他客戶程式的可能性小。這實際上就是介面汙染的問題。
2.對介面的汙染
過於臃腫的介面設計是對介面的汙染。所謂的介面汙染就是為介面添加不必要的職責,如果開發人員在介面中增加一個新功能的目的只是減少介面實作類別的數目,則此設計將導致介面被不斷地“汙染”並“變胖”。
“介面隔離”其實就是定製化服務設計的原則。使用介面的多重繼承實現對不同的介面的組合,從而對外提供組合功能---達到“按需提供服務”。
介面即要拆,但也不能拆得太細,這就得有個標準,這就是高內聚。介面應該具備一些基本的功能,能獨一完成一個基本的任務。
在實際應用中,會遇到如下問題:比如,我需要一個能適配多種類型資料庫的DAO實現,那麼首先應實現一個資料庫操作的介面,其中規定一些資料庫操作的基本方法,比如串連資料庫、增刪改查、關閉資料庫等。這是一個最少功能的介面。對於一些MySQL中特有的而其他資料庫裡並不存在的或性質不同的方法,如PHP裡可能用到的MySQL的pconnect方法,其他資料庫裡並不存在和這個方法相同的概念,這個方法也就不應該出現在這個基本的介面裡,那這個基本的介面應該有哪些基本的方法呢?PDO已經告訴你了。
PDO是一個抽象的資料庫介面層,它告訴我們一個基本的資料庫操作介面應該實現哪些基本的方法。介面是一個高層次的抽象,所以介面裡的方法都應該是通用的、基本的、不易變化的。
還有一個問題,那些特有的方法應該怎麼實現?根據ISP原則,這些方法可以在別一個介面中存在,讓這個“異類”同時實現這兩個介面。
對於介面的汙染,可以考慮這兩條處理方式:
利用委託分離介面。
利用多繼承分離介面。
委託模式中,有兩個對象參與處理同一個請求,接受請求的對象將請求委託給另一個對象來處理,如策略模式、代理模式等中都應用到了委託的概念。
再來看一下執行個體說明
你是否遇到過非常“胖”的介面呢?
舉個例子來說吧:有一個跟動物有關的介面,代碼如下:
<?phpinterface Animal{ public function walk(); public function speak();}
狗是這個介面的一個具體實現:
<?phprequire_once "animal.php";class Dog implements Animal{ public function walk(){ echo "dogs can walk"; } public function speak(){ echo "dogs can speak"; }}
ok,現在我們想建立一個魚類,它會遊泳,怎麼辦呢?我們必須要修改介面,還會影響到dog類的實現,而fish也需要實現walk和speak方法,如下代碼所示:
Animal介面類:
<?phpinterface Animal{ public function walk(); public function speak(); public function swim();}
dog類:
<?phprequire_once "animal.php";class Dog implements Animal{ public function walk(){ echo "dogs can walk"; } public function speak(){ echo "dogs can speak"; } public function swim(){ }}
fish類:
<?phprequire_once "animal.php";class Fish implements Animal{ public function walk(){ } public function speak(){ } public function swim(){ echo "fish can swim"; }}
這時Animal介面類就呈現出了”胖“介面的特徵了。所謂胖介面其實就是介面中定義了不是所有實作類別都需要的方法,就像Animal介面類,有些動物是不會遊泳的,有些動物是不會行走的,還有些動物是不會飛的。如果將這些方法都寫在一個Animal介面類中,那麼後期的擴充和維護簡直就是一場災難。
那麼,怎麼解決以上問題呢?
很簡單,介面細化即可,將Animal介面類拆分成三個介面類:
animalCanWalk介面類:
<?phpinterface animalCanSpeak{ public function speak();}
AnimalCanSwim介面類:
<?phpinterface AnimalCanSwim{ public function swim();}
animalCanSpeak介面類:
<?phpinterface animalCanSpeak{ public function speak();}
定義好這幾個介面類之後,dog和fish的實現就容易多了,
<?phprequire_once "animalCanSpeak.php";require_once "animalCanWalk.php";class Dog implements animalCanSpeak,animalCanWalk{ public function walk(){ echo "dogs can walk"; } public function speak(){ echo "dogs can speak"; }}
<?phprequire_once "animalCanSwim.php";class Fish implements AnimalCanSwim{ public function swim(){ echo "fish can swim"; }}
總結一下:
介面隔離原則(Interface Segregation Principle, ISP)的概念:使用多個專門的介面,而不使用單一的總介面,即用戶端不應該依賴那些它不需要的介面。
在使用介面隔離原則時,我們需要注意控制介面的粒度,介面不能太小,如果太小會導致系統中介面泛濫,不利於維護;介面也不能太大,太大的介面將違背介面隔離原則,靈活性較差,使用起來很不方便。一般而言,介面中僅包含為某一類使用者定製的方法即可,不應該強迫客戶依賴於那些它們不用的方法。
相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!
推薦閱讀:
PHP依賴倒置案例詳解
PHP建立Composer包步驟詳解