物件導向設計原則之介面隔離原則

Liuwei-Sunny發表於2012-05-13

      介面隔離原則定義如下:

介面隔離原則(Interface  Segregation Principle, ISP):使用多個專門的介面,而不使用單一的總介面,即客戶端不應該依賴那些它不需要的介面。

      根據介面隔離原則,當一個介面太大時,我們需要將它分割成一些更細小的介面,使用該介面的客戶端僅需知道與之相關的方法即可。每一個介面應該承擔一種相對獨立的角色,不幹不該乾的事,該乾的事都要幹。這裡的介面往往有兩種不同的含義:一種是指一個型別所具有的方法特徵的集合,僅僅是一種邏輯上的抽象;另外一種是指某種語言具體的介面定義,有嚴格的定義和結構,比如Java語言中的interface。對於這兩種不同的含義,ISP的表達方式以及含義都有所不同:

      (1) 當把“介面”理解成一個型別所提供的所有方法特徵的集合的時候,這就是一種邏輯上的概念,介面的劃分將直接帶來型別的劃分。可以把介面理解成角色,一個介面只能代表一個角色,每個角色都有它特定的一個介面,此時,這個原則可以叫做角色隔離原則

      (2) 如果把“介面”理解成狹義的特定語言的介面,那麼ISP表達的意思是指介面僅僅提供客戶端需要的行為,客戶端不需要的行為則隱藏起來,應當為客戶端提供儘可能小的單獨的介面,而不要提供大的總介面在物件導向程式語言中,實現一個介面就需要實現該介面中定義的所有方法,因此大的總介面使用起來不一定很方便,為了使介面的職責單一,需要將大介面中的方法根據其職責不同分別放在不同的小介面中,以確保每個介面使用起來都較為方便,並都承擔某一單一角色。介面應該儘量細化,同時介面中的方法應該儘量少,每個介面中只包含一個客戶端(如子模組或業務邏輯類)所需的方法即可,這種機制也稱為定製服務,即為不同的客戶端提供寬窄不同的介面。

      下面通過一個簡單例項來加深對介面隔離原則的理解:

      Sunny軟體公司開發人員針對某CRM系統的客戶資料顯示模組設計瞭如圖1所示介面,其中方法dataRead()用於從檔案中讀取資料,方法transformToXML()用於將資料轉換成XML格式,方法createChart()用於建立圖表,方法displayChart()用於顯示圖表,方法createReport()用於建立文字報表,方法displayReport()用於顯示文字報表。

初始設計方案結構圖

      在實際使用過程中發現該介面很不靈活,例如如果一個具體的資料顯示類無須進行資料轉換(原始檔本身就是XML格式),但由於實現了該介面,將不得不實現其中宣告的transformToXML()方法(至少需要提供一個空實現);如果需要建立和顯示圖表,除了需實現與圖表相關的方法外,還需要實現建立和顯示文字報表的方法,否則程式編譯時將報錯。

      現使用介面隔離原則對其進行重構。

      在圖1中,由於在介面CustomerDataDisplay中定義了太多方法,即該介面承擔了太多職責,一方面導致該介面的實現類很龐大,在不同的實現類中都不得不實現介面中定義的所有方法,靈活性較差,如果出現大量的空方法,將導致系統中產生大量的無用程式碼,影響程式碼質量;另一方面由於客戶端針對大介面程式設計,將在一定程式上破壞程式的封裝性,客戶端看到了不應該看到的方法,沒有為客戶端定製介面。因此需要將該介面按照介面隔離原則和單一職責原則進行重構,將其中的一些方法封裝在不同的小介面中,確保每一個介面使用起來都較為方便,並都承擔某一單一角色,每個介面中只包含一個客戶端(如模組或類)所需的方法即可。

      通過使用介面隔離原則,本例項重構後的結構如圖2所示:

2 重構後的結構圖

      在使用介面隔離原則時,我們需要注意控制介面的粒度,介面不能太小,如果太小會導致系統中介面氾濫,不利於維護;介面也不能太大,太大的介面將違背介面隔離原則,靈活性較差,使用起來很不方便。一般而言,介面中僅包含為某一類使用者定製的方法即可,不應該強迫客戶依賴於那些它們不用的方法。

擴充套件

在《敏捷軟體開發——原則、模式與實踐》一書中,RobertC. Martin從解決“介面汙染”的角度對介面隔離原則進行了詳細的介紹,大家可以參閱該書第12章——介面隔離原則(ISP)進行深入的學習。

 【作者:劉偉  http://blog.csdn.net/lovelion

 

相關文章