間接在分層架構中體現尤為明顯,引入層實則就是引入間接性。利用間接對變化進行隔離,使得變化只能影響一層。例如在領域層與資料庫之間引入資料訪問層,就可以隔絕因為資料庫發生的變化對領域帶來的影響。
在分層架構中,我們應盡量保證在某一層中所有用到的元件都工作在同乙個抽象層中,這意味著需要謹慎處理物件之間的協作,盡量避免跨層之間的呼叫。如果不同的層部署在不同的伺服器,就會帶來不必要的訊息處理,增加了網路跳數與頻寬占用。拋開效能不談,跨層呼叫產生的依賴,可能破壞層的內聚性。倘若必須依賴於底層,我們也應該減少對底層的依賴點。要減少這種依賴,可以在同一層中提供乙個間接介面,用於處理對底層的依賴關係,從而將變化集中於一處。
對於模組和元件中的物件協作,同樣遵循這一原則。假設系統定義了報表引擎元件,它需要呼叫資料引擎元件提供的服務,驅動引擎執行資料庫查詢,以獲得報表所必須的資料。一般採用的設計如下圖所示:
inte***ce dataenginerepository
在dataenginerepository的實現類中,注入了dataengineservice物件:
public
class dataenginerepositoryimpl
implements dataenginerepository
public dataengineservice getdataengineservice()
public
void setdataengineservice(
dataengineservice dataengineservice)
} 既然dataengineservice介面已經提供了合理的抽象,引入dataenginerepository介面會否是多餘的呢?現在的他,看起來像是一名呆瓜接力選手,剛剛接到接力棒,就驚慌失措地趕緊塞給下乙個人手中了。然而,經過仔細分析,我們還是能夠看到二者的細微區別。在沒有引入dataenginerepository介面之前,報表引擎中的領域物件都依賴於跨元件的dataengineservice;現在,這些領域物件只需依賴同乙個元件中的dataenginerepository即可。這意味著什麼呢?我們可以比較下面的兩個元件圖:
間接引入的好處只有在變化時,才能凸顯出來。我們的專案確實遭遇了變化。我們不希望看到reportengine元件直接依賴於dataengine,因為報表對資料的訪問不應該是直接的,它需要受到許可權、安全的限制,同時可能還需要控制相關的業務。為此,我們在reportengine與dataengine之間,引入了functionengine,用以實現功能的控制與分發。現在,reportengine應該依賴於functionengine,而不是dataengine。
public
class dataenginerepositoryimpl
implements dataenginerepository
public functionexecutor getfunctionexecutor()
public
void setfunctionexecutor(
functionexecutor functionexecutor)
} 修改dataenginerepositoryimpl類的實現,並不會影響報表引擎中的領域物件,資料引擎也維持了自身的穩定。或許有人認為,即使不引入dataenginerepository介面,功能引擎帶來的變化也不會影響原有的設計,因為dataengineservice是抽象的介面,我們只需要修改它的實現即可。可是,切勿忘記這裡的變化牽涉到功能引擎,修改dataengineservice的實現類,就意味著需要在它的實現中執行對功能引擎的呼叫;而功能引擎又必須呼叫資料引擎,從而帶來functionengine與dataengine之間的迴圈依賴。沒有比迴圈依賴更糟糕的依賴關係了!
OOP封裝 隔離變化
封裝 保護程式的隱私,不該讓呼叫者知道的事,堅決不能暴露出來。具體實現細節做法 隱藏內部函式 隱藏內部函式的做法 禁用全域性變數 當把程式從單執行緒該為多執行緒,對併發的程式產生不利影響。更重的是直接使用全域性變數,會造成呼叫者和實現者之間的耦合。學習摘錄自 系統程式設計師成長計畫 像c 具有oop...
OOD 隔離變化 橋接模式
正如電腦主機和顯示器之間,主機的配置千變萬化,不斷公升級,顯示器可能公升級緩慢。如果這時你買的是一體機,硬體公升級就要受到限制。這就是乙個典型的分離變化的需求場景。在應用中,乙個業務會有多個協作者,直接耦合會導致其中乙個類的變化就會影響其它類的行為。這時最好的做法是對行為進行抽象,區分出變與不變,或...
封裝變化(三)
設想這樣乙個需求,我們需要為自己的框架提供乙個負責排序的元件。目前需要實現的是氣泡排序演算法和快速排序演算法,根據 面向介面程式設計 的思想,我們可以為這些排序演算法提供乙個統一的介面isort,在這個介面中有乙個方法sort 它能接受乙個object陣列引數。對陣列進行排序後,返回該陣列。介面的定...