經過前面兩篇,我想各位朋友對「面向接口編程」的思想有了必定認識,並經過第二篇的例子,得到了必定的直觀印象。可是,第二篇中的例子旨在展現面向接口編程的實現方法,比較簡單,不能體現出面向接口編程的優點和這種思想的內涵。那麼,這一篇做爲本系列的終結篇,將經過分析幾個比較有深度的模式或架構,解析隱藏其背後的面向接口思想。這篇我將要分析的分別是MVC模式和.NET平臺的分層架構。編程
這篇的內容可能會比較抽象,望諒解。設計模式
1. 從MVC開始架構
MVC簡介:學習
本文不打算詳細解釋MVC架構,而是把重點放在其中的面向接口思想上。因此在這裏,只對MVC作一個簡略的介紹。翻譯
MVC是一種用於表示層設計的複合設計模式。M、V、C分別表示模型(Model)、View(視圖)、Controller(控制器)。它們的職責以下:設計
模型:用於存儲應用中的數據及運行邏輯,是應用的實體。server
視圖:負責可視部分,用於與用戶交互及呈現數據。視圖只負責顯示,不負責將用戶的操做行爲解釋給模型。對象
控制器:負責將用戶的行爲解釋給模型。根據指定的策略和用戶的操做,調用模型的邏輯。blog
關於三者的關係,我畫了一張圖,你們請看:
MVC模式示意
它們之間的交互有如下幾種:
1. 當用戶在視圖上作任何須要調用模型的操做時,它的請求將被控制器截獲。
2. 控制器按照自身指定的策略,將用戶行爲翻譯成模型操做,調用模型相應邏輯實現。
3. 控制器可能會在接到視圖操做時,指定視圖作某些改變。
4. 當模型的狀態發生改變時,將經過某種方式通知視圖。
5. 視圖能夠從模型獲取狀態,從而改變本身的顯示。
MVC介紹完了,那麼可能會有人問,咱們的主題呢?面向接口思想呢?其實,MVC中到處都存在面向接口的影子。下面,我對其中幾個側面進行解釋。
1. 首先咱們能夠看到,視圖和模型是有直接交互的,也就是上面的四、5兩點。可是有一點可能會讓你吃驚:它們兩個誰也不「認識」誰,即它們相互並不知道對方是作什麼的、有什麼屬性、有什麼方法,可是它們能交互。這是怎麼作到的呢?由於它們個各知道對方實現了某一個接口。
此乃面向接口思想一大做用:使相互不認識的類進行交互。這樣作是頗有好處的,首先它們之間的耦合度大大下降,其次雙方均可以進行替換,只要實現了相同的接口,就沒有問題。
打個不太恰當的比喻。咱們都知道120這個電話號碼,是急救電話。其實120就是個接口,由於當你撥打這個電話時,你不知道那邊是哪所醫院,甚至不知道那邊是否是醫院,你只知道電話那頭的地方能夠救人,也能夠說實現了IHelp接口。這樣,你經過一個號碼能夠說同所有的救人機構聯繫起來了,當有緊急事件,接線控制那邊會將你的請求接到最近可用的機構,你就能夠最快的獲得幫助。
如今咱們假設沒有使用面向接口思想,來看看會發生什麼恐怖的事情:首先,我家的120號碼是綁定在本市第一人民醫院的,即當我撥打120時,只能撥通第一人民醫院。若是有一天我食物中毒了,急忙撥通了120,可是電話那邊告訴我他們醫院的救護車都派出去了,我問那怎麼接通別家醫院的電話,那邊的MM很溫柔的告訴我,讓我打電話給網通公司,而後從新爲我佈線。因而我吐血而亡……
言歸正傳。這裏,我要引入一個設計模式,叫觀察着(Observer)模式。這個模式大約是這樣的:整個模式中有兩種實體:觀察者和被觀察者,它們分別實現一個接口,這裏咱們姑且叫作IObserver與IObserverSubject。IObserver只有一個方法,例如叫Update,當被觀察者狀態改變時,調用這個方法,用來通知觀察者。IObserverSubject接口有兩個方法,都是供觀察者調用。一個用來將觀察者註冊爲此被觀察者的觀察對象,另外一個用於將觀察者移除。
通常狀況下,一個被觀察者對應多個觀察者。
在MVC中,視圖是觀察者,模型是被觀察者,當模型狀態改變時,調用全部觀察者的Update方法,通知視圖模型有變,視圖在Update方法裏寫下響應代碼,完成操做。經過這個方法,視圖和模型就能夠在僅依賴接口的情形下進行交互,而沒必要強耦合,並且在模型不變的狀況下,視圖能夠隨意替換。(只要實現了IObserver)
2. 在MVC中另外一個使用接口的地方就是控制器,這裏我要首先引入一個設計模式:策略模式(Strategy)。在MVC中,控制器就使用了這個模式。
剛纔我說過,視圖負責與用戶交互,可是,它只負責界面顯示部分,至於當用戶作了某個操做(如單擊某個按鈕)後系統應該怎麼反應,視圖並不負責,它只是將這個動做交給控制器,控制器根據內置的策略,將用戶操做翻譯成模型的邏輯。這就是說,同一個視圖、同一種操做,模型能夠作出不一樣的反應,這取決與控制器的內置策略。因此,咱們的系統中能夠有不少控制器,它們有不一樣的策略,當視圖但願改變策略時,它能夠更換控制器。怎麼實現呢?這就須要視圖不能和具體控制器耦合,而是要僅依賴一個控制器接口(如IController),並聚合一個IController的實例。當但願更改策略時,能夠在系統運行時動態更換Controller,這就是策略模式的實現。
關於MVC的接口思想就先介紹到這裏。其實MVC中還有不少地方用到面向接口,因爲本文不是專門介紹MVC或設計模式的,因此對用到的模式沒有作詳解,而是把重點放在其中的面向接口思想上。若是沒有設計模式的基礎,讀上文可能會有些困難,但願各位見諒!我打算在之後專門寫文章來解析MVC。
2. .NET平臺下分層架構的面向接口思想
咱們知道,在作大一點的系統應用時(特別是B/S架構),比較好的方法是分層架構。所謂分層架構,是指將系統從職責上分紅若干層,每層各司其職,上層依賴下層完成操做。
在.NET平臺上,比較經典的分層架構是三層架構,從下到上依次是:數據訪問層、業務邏輯層、表示層。各層職責以下:
數據訪問層:負責與數據源交互,完成數據訪問等一系列操做。
業務邏輯層:完成與系統業務有關的邏輯操做。
表示層:負責與用戶交互、呈現數據等一切與系統表示有關的操做。
剛纔咱們說過,分層架構下是向下依賴的(不考慮依賴倒置),也就是業務邏輯層要調用數據訪問層完成與數據源有關的操做,而表示層調用業務邏輯層完成業務邏輯工做。可是,表示層對數據訪問層是沒有依賴的。
在這個架構中,每一層都不是一個類,而是一個類族,例如,在一個CMS系統中,數據訪問層可能會有一系列的類,分別負責用戶、文章、評論等業務實體的數據訪問操做,而業務邏輯層也同樣。若是咱們直接依賴,即業務邏輯層實例化數據訪問層的類,表示層再實例化業務邏輯層的類,會形成強耦合。若是我想把數據庫從SQLServer換成MySQL,則要改變整個業務邏輯層代碼,這是個很差的設計。(還記得「開放-關閉」原則嗎)因此,通常的作法是,爲數據訪問層和業務邏輯層分別定義一族接口,業務邏輯層不依賴具體的數據訪問層,而是僅依賴數據訪問層的接口族,表示層也同樣,依賴業務邏輯層的接口族。如此一來,當要更換數據庫時,咱們就沒必要改寫整個業務邏輯層,由於業務邏輯層里根本沒有任何數據訪問層中的具體類,而全是經過接口實現的。在.NET中,只要配合配置文件和反射機制,再運用Abstract Factory設計模式,就能夠實現「依賴注入」,即在不改動代碼的狀況下根據配置選擇相應的層次組件。這樣,咱們就能夠爲不通數據庫分別實現數據訪問層,也能夠編寫ORM的數據訪問層,甚至是基於XML的,只要實現了數據訪問層接口族,就能夠和業務邏輯層無縫鏈接,從而極大提升了軟件的靈活性和可維護性。固然要更改業務邏輯層也是同樣。
若是說,前面的例子都是從微觀視角討論接口,那麼,這個例子則從宏觀視角展示了面向接口編程的內涵和優點。很抱歉在這裏不能對這個架構深刻講解,有興趣的朋友能夠參考微軟的官方示例.NET PetShop4。(可是請注意,這個示例中業務邏輯層沒有定義接口族,而是強耦合於表示層中,這多是由於考慮到在這個系統中業務邏輯沒有更改的可能。另外因爲是個示例,不是真正的B2C系統,因此業務邏輯層很簡單。)
好了,本系列文章就到這裏。但願各位朋友經過這三篇文章,能對「面向接口編程」有必定的瞭解。固然,我只是起到一個拋磚引玉的做用,其真正的內涵和精髓,還須要各位從實踐中慢慢認識。還有,就是面向接口思想不是孤立的,它和設計模式等內容都是面向對象大系中的精華,並且是相互滲透、相互聯繫的。其實,不少設計模式就是面向接口思想的體現。咱們應該把這些放在一塊兒學習,從而真正提供本身的面向對象思考能力和實戰能力。