面向接口編程解析

相信經常使用設計模式的碼農對面向接口編程已經有一定的瞭解,因爲在各種設計模式當中,對面向接口的各種應用可謂是發揮得淋漓盡致。

什麼是面向接口編程呢?我個人的定義是:在系統分析和架構中,分清層次和依賴關係,每個層次不是直接向其上層提供服務(即不是直接實例化在上層中),而是通過定義一組接口,僅向上層暴露其接口功能,上層對於下層僅僅是接口依賴,而不依賴具體類。

這樣做的好處是顯而易見的,首先對系統靈活性大有好處。當下層需要改變時,只要接口及接口功能不變,則上層不用做任何修改。甚至可以在不改動上層代碼時將下層整個替換掉,實現了程序的可插拔性,對於不同的需求切換不同的實現,降低了耦合度,隨着系統複雜性的提高這個優勢會越來越明顯。

我們都知道造電腦主板的不可能等CUP造好再開工,也不用等顯示器先造好的,是因爲各廠商只需要把自己的產品接口按預先規定的設定來建造就可以實現跟其它部件進行對接了,所以使用接口的另一個好處就是不同部件或層次的開發人員可以並行開工,只要接口一致,設計合理,完全可以並行進行開發,從而提高效率。

說到面向接口,那肯定就會聯想到面向對象了,他們兩個的關係不是敵對的,而是附屬的。首先,面向接口編程和麪向對象編程並不是平級的,它並不是比面向對象編程更先進的一種獨立的編程思想,而是附屬於面向對象思想體系,屬於其一部分。或者說,它是面向對象編程體系中的思想精髓之一。

接下來從模式或架構中瞭解這種編程方式的優勢和這種思想的內涵。

一、從大家都比較熟悉的MVC開始

MVC簡介:本文不打算詳細解釋MVC架構,而是把重點放在其中的面向接口思想上。所以在這裏,只對MVC做一個簡略的介紹。MVC是一種用於表示層設計的複合設計模式。M、V、C分別表示模型(Model)、View(視圖)、Controller(控制器)。它們的職責如下:

模型:用於存儲應用中的數據及運行邏輯,是應用的實體。

視圖:負責可視部分,用於與用戶交互及呈現數據。視圖只負責顯示,不負責將用戶的操作行爲解釋給模型。

控制器:負責將用戶的行爲解釋給模型。根據指定的策略和用戶的操作,調用模型的邏輯。

它們之間的交互有以下幾種:

1.當用戶在視圖上做任何需要調用模型的操作時,它的請求將被控制器 截獲。

2.控制器按照自身指定的策略,將用戶行爲翻譯成模型操作,調用模型相應邏輯實現。

3.控制器可能會在接到視圖操作時,指定視圖做某些改變。

4.當模型的狀態發生改變時,將通過某種方式通知視圖。

5.視圖可以從模型獲取狀態,從而改變自己的顯示。

接下來就是我們的主題了

1.首先我們可以看到,視圖和模型是有直接交互的,也就是上面的4、5兩點。這就奇怪了:這兩個不同層面的業務,都有自己各自的封裝,甚至是由不同人員開發管的,即它們相互並不知道對方是做什麼的、有什麼屬性、有什麼方法,但是它們能交互。這是怎麼做到的呢?因爲它們個各知道對方實現了某一接口。此乃面向接口思想一大作用:使相互不認識的類進行交互。這樣做是很有好處的,首先它們之間的耦合度大大降低,其次雙方都可以進行替換,只要實現了相同的接口,就沒有問題。

這裏,要引入一個設計模式,叫觀察着(Observer)模式。整個模式中有兩種實體:觀察者和被觀察者,它們分別實現一個接口,這裏我們姑且叫做IObserver與IObserverSubject。IObserver只有一個方法,例如叫Update,當被觀察者狀態改變時,調用這個方法,用來通知觀察者。IObserverSubject接口有兩個方法,都是供觀察者調用。一個用來將觀察者註冊爲此被觀察者的觀察對象,另一個用於將觀察者移除。一般情況下,一個被觀察者對應多個觀察者,耦合的雙方都依賴於抽象而不是依賴於具體實現,這樣使得各自實現的改變都不會導致另一方需要修改實現。

在MVC中,視圖是觀察者,模型是被觀察者,當模型狀態改變時,調用所有觀察者的Update方法,通知視圖模型有變,視圖在Update方法裏寫下響應代碼,完成操作。通過這個方法,視圖和模型就可以在僅依賴接口的情形下進行交互,而不必強耦合,而且在模型不變的情況下,視圖可以隨意替換。(只要實現了IObserver)

2. 在MVC中另一個使用接口的地方就是控制器,這裏要首先引入一個設計模式:策略模式(Strategy)。在MVC中,控制器就使用了這個模式。

剛纔說過,視圖負責與用戶交互,但是,它只負責界面顯示部分,至於當用戶做了某個操作(如單擊某個按鈕)後系統應該怎麼反應,視圖並不負責,它只是將這個動作交給控制器,控制器根據內置的策略,將用戶操作翻譯成模型的邏輯。這就是說,同一個視圖、同一種操作,模型可以做出不同的反應,這取決與控制器的內置策略。所以,我們的系統中可以有很多控制器,它們有不同的策略,當視圖希望改變策略時,它可以更換控制器。怎麼實現呢?這就需要視圖不能和具體控制器耦合,而是要僅依賴一個控制器接口(如IController),並聚合一個IController的實例。當希望更改策略時,可以在系統運行時動態更換Controller,這就是策略模式的實現。

關於MVC的接口思想就先介紹到這裏。其實MVC中還有很多地方用到面向接口,由於本文不是專門介紹MVC或設計模式的,所以對用到的模式沒有做詳解,而是把重點放在其中的面向接口思想上。如果沒有設計模式的基礎,讀上文可能會有些困難,建議可以找些關於設計模式的書籍閱讀,因爲設計模式也是日常開發中相當重要的一部分知識。

二、分層架構的面向接口思想

我們知道,在做大一點的系統應用時(特別是B/S架構),比較好的方法是分層架構。所謂分層架構,是指將系統從職責上分成若干層,每層各司其職,上層依賴下層完成操作。

比較經典的分層架構是三層架構,從下到上依次是:數據訪問層、業務邏輯層、表示層。各層職責如下:

數據訪問層:負責與數據源交互,完成數據訪問等一系列操作。

業務邏輯層:完成與系統業務有關的邏輯操作。

表示層:負責與用戶交互、呈現數據等一切與系統表示有關的操作。

剛纔我們說過,分層架構是向下依賴的,也就是業務邏輯層要調用數據訪問層完成與數據源有關的操作,而表示層調用業務邏輯層完成業務邏輯工作。但是,表示層對數據訪問層是沒有依賴的。

在這個架構中,每一層都不是一個類,而是一個類族,例如,在一個CMS系統中,數據訪問層可能會有一系列的類,分別負責用戶、文章、評論等業務實體的數據訪問操作,而業務邏輯層也一樣。如果我們直接依賴,即業務邏輯層實例化數據訪問層的類,表示層再實例化業務邏輯層的類,會造成強耦合。如果我想把數據庫從SQLServer換成MySQL,則要改變整個業務邏輯層代碼,這是個不好的設計。(還記得“開放-關閉”原則嗎)所以,一般的做法是,爲數據訪問層和業務邏輯層分別定義一族接口,業務邏輯層不依賴具體的數據訪問層,而是僅依賴數據訪問層的接口族,表示層也一樣,依賴業務邏輯層的接口族。如此一來,當要更換數據庫時,我們就不必改寫整個業務邏輯層,因爲業務邏輯層里根本沒有任何數據訪問層中的具體類,而全是通過接口實現的。只要配合配置文件和反射機制,再運用Abstract Factory設計模式,就可以實現“依賴注入”,即在不改動代碼的情況下根據配置選擇相應的層次組件。這樣,我們就可以爲不通數據庫分別實現數據訪問層,也可以編寫ORM的數據訪問層,甚至是基於XML的,只要實現了數據訪問層接口族,就可以和業務邏輯層無縫連接,從而極大提高了軟件的靈活性和可維護性。當然要更改業務邏輯層也是一樣。

第一個例子是從微觀的角度對面向接口編程進行解析,第二個例子則是從宏觀的角度來解析 。

最後歡迎各位大神發表自己的見解

發佈了78 篇原創文章 · 獲贊 26 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章