好的軟件架構設計

什么是架構

前言:軟體設計師中有一些技術水平較高、經驗較為豐富的人,他們需要承擔軟件系統的架構設計,也就是需要設計系統的元件如何劃分、元件之間如何發生相互作用,以及系統中邏輯的、物理的、系統的重要決定的作出。在很多公司中,架構師不是一個專門的和正式的職務。通常在一個開發小組中,最有經驗的程序員會負責一些架構方面的工作。在一個部門中,最有經驗的項目經理會負責一些架構方面的工作。但是,越來越多的公司體認到架構工作的重要性。

  什么是軟件系統的架構(Architecture)?一般而言,架構有兩個要素:

  ·它是一個軟件系統從整體到部分的最高層次的劃分。

  一個系統通常是由元件組成的,而這些元件如何形成、相互之間如何發生作用,則是關于這個系統本身結構的重要信息。

  詳細地說,就是要包括架構元件(Architecture Component)、聯結器(Connector)、任務流(Task-flow)。所謂架構元素,也就是組成系統的核心"磚瓦",而聯結器則描述這些元件之間通訊的路徑、通訊的機制、通訊的預期結果,任務流則描述系統如何使用這些元件和聯結器完成某一項需求。

  ·建造一個系統所作出的最高層次的、以后難以更改的,商業的和技術的決定。

  在建造一個系統之前會有很多的重要決定需要事先作出,而一旦系統開始進行詳細設計甚至建造,這些決定就很難更改甚至無法更改。顯然,這樣的決定必定是有關系統設計成敗的最重要決定,必須經過非常慎重的研究和考察。

  計算機軟件的歷史開始于五十年代,歷史非常短暫,而相比之下建筑工程則從石器時代就開始了,人類在幾千年的建筑設計實踐中積累了大量的經驗和教訓。建筑設計基本上包含兩點,一是建筑風格,二是建筑模式。獨特的建筑風格和恰當選擇的建筑模式,可以使一個獨一無二。

  下面的照片顯示了中美洲古代瑪雅建筑,Chichen-Itza大金字塔,九個巨大的石級堆壘而上,九十一級臺階(象征著四季的天數)奪路而出,塔頂的神殿聳入云天。所有的數字都如日歷般嚴謹,風格雄渾。難以想象這是石器時代的建筑物。



圖1、位于墨西哥Chichen-Itza(在瑪雅語中chi意為嘴chen意為井)的古瑪雅建筑。(攝影:作者)

  軟件與人類的關系是架構師必須面對的核心問題,也是自從軟件進入歷史舞臺之后就出現的問題。與此類似地,自從有了建筑以來,建筑與人類的關系就一直是建筑設計師必須面對的核心問題。英國首相丘吉爾說,我們構造建筑物,然后建筑物構造我們(We shape our buildings, and afterwards our buildings shape us)。英國下議院的會議廳較狹窄,無法使所有的下議院議員面向同一個方向入座,而必須分成兩側入座。丘吉爾認為,議員們入座的時候自然會選擇與自己政見相同的人同時入座,而這就是英國政黨制的起源。Party這個詞的原意就是"方"、"面"。政黨起源的關鍵就是建筑物對人的影響。

  在軟件設計界曾經有很多人認為功能是最為重要的,形式必須服從功能。與此類似地,在建筑學界,現代主義建筑流派的開創人之一Louis Sullivan也認為形式應當服從于功能(Forms follows function)。

  幾乎所有的軟件設計理念都可以在浩如煙海的建筑學歷史中找到更為遙遠的歷史回響。最為著名的,當然就是模式理論和XP理論。

  架構的目標是什么

  正如同軟件本身有其要達到的目標一樣,架構設計要達到的目標是什么呢?一般而言,軟件架構設計要達到如下的目標:

  ·可靠性(Reliable)。軟件系統對于用戶的商業經營和管理來說極為重要,因此軟件系統必須非常可靠。

  ·安全行(Secure)。軟件系統所承擔的交易的商業價值極高,系統的安全性非常重要。

  ·可擴展性(Scalable)。軟件必須能夠在用戶的使用率、用戶的數目增加很快的情況下,保持合理的性能。只有這樣,才能適應用戶的市場擴展得可能性。

  ·可定制化(Customizable)。同樣的一套軟件,可以根據客戶群的不同和市場需求的變化進行調整。

  ·可擴展性(Extensible)。在新技術出現的時候,一個軟件系統應當允許導入新技術,從而對現有系統進行功能和性能的擴展

  ·可維護性(Maintainable)。軟件系統的維護包括兩方面,一是排除現有的錯誤,二是將新的軟件需求反映到現有系統中去。一個易于維護的系統可以有效地降低技術支持的花費

  ·客戶體驗(Customer Experience)。軟件系統必須易于使用。

  ·市場時機(Time to Market)。軟件用戶要面臨同業競爭,軟件提供商也要面臨同業競爭。以最快的速度爭奪市場先機非常重要。

  架構的種類

  根據我們關注的角度不同,可以將架構分成三種:

  ·邏輯架構、軟件系統中元件之間的關系,比如用戶界面,數據庫,外部系統接口,商業邏輯元件,等等。

  比如下面就是筆者親身經歷過的一個軟件系統的邏輯架構圖

?

圖2、一個邏輯架構的例子

  從上面這張圖中可以看出,此系統被劃分成三個邏輯層次,即表象層次,商業層次和數據持久層次。每一個層次都含有多個邏輯元件。比如WEB服務器層次中有HTML服務元件、Session服務元件、安全服務元件、系統管理元件等。

  ·物理架構、軟件元件是怎樣放到硬件上的。

  比如下面這張物理架構圖描述了一個分布于北京和上海的分布式系統的物理架構,圖中所有的元件都是物理設備,包括網絡分流器、代理服務器、WEB服務器、應用服務器、報表服務器、整合服務器、存儲服務器、主機等等。

?

圖3、一個物理架構的例子

  ·系統架構、系統的非功能性特征,如可擴展性、可靠性、強壯性、靈活性、性能等。

  系統架構的設計要求架構師具備軟件和硬件的功能和性能的過硬知識,這一工作無疑是架構設計工作中最為困難的工作。

  此外,從每一個角度上看,都可以看到架構的兩要素:元件劃分和設計決定。

  首先,一個軟件系統中的元件首先是邏輯元件。這些邏輯元件如何放到硬件上,以及這些元件如何為整個系統的可擴展性、可靠性、強壯性、靈活性、性能等做出貢獻,是非常重要的信息。

  其次,進行軟件設計需要做出的決定中,必然會包括邏輯結構、物理結構,以及它們如何影響到系統的所有非功能性特征。這些決定中會有很多是一旦作出,就很難更改的。

  根據作者的經驗,一個基于數據庫的系統架構,有多少個數據表,就會有多少頁的架構設計文檔。比如一個中等的數據庫應用系統通常含有一百個左右的數據表,這樣的一個系統設計通常需要有一百頁左右的架構設計文檔。

  架構師

  軟體設計師中有一些技術水平較高、經驗較為豐富的人,他們需要承擔軟件系統的架構設計,也就是需要設計系統的元件如何劃分、元件之間如何發生相互作用,以及系統中邏輯的、物理的、系統的重要決定的作出。

  這樣的人就是所謂的架構師(Architect)。在很多公司中,架構師不是一個專門的和正式的職務。通常在一個開發小組中,最有經驗的程序員會負責一些架構方面的工作。在一個部門中,最有經驗的項目經理會負責一些架構方面的工作。

  但是,越來越多的公司體認到架構工作的重要性,并且在不同的組織層次上設置專門的架構師位置,由他們負責不同層次上的邏輯架構、物理架構、系統架構的設計、配置、維護等工作。

軟件的架構設計

好的開始相當于成功一半

開始之初的架構設計決定著軟件產品的生死存亡。“好的開始相當于成功一半”。

開始的架構設計也是最難的,需要調研同類產品的情況以及技術特征,了解當前世界上對這種產品所能提供的理論支持和技術平臺支持。再結合自己項目的特點(需要透徹的系統分析),才能逐步形成自己項目的架構藍圖。

比如要開發網站引擎系統,就從Yahoo的個人主頁生成工具到虛擬主機商提供的網站自動生成系統,以及IBM Webphere Portal的特點和局限 從而從架構設計角度定立自己產品的位置。

好的設計肯定需要經過反復修改,從簡單到復雜的循環測試是保證設計正確的一個好辦法

由于在開始選擇了正確的方向,后來項目的實現過程也驗證了這種選擇,但在一些架構設計的細部方面,還需要對方案進行修改,屬于那種螺旋上升的方式,顯然這是通過測試第一的思想和XP工程方法來實現的。

如果我們開始的架構設計在技術平臺定位具有一定的世界先進水平,那么,項目開發實際有一半相當于做實驗,是研發,存在相當的技術風險。

因此,一開始我們不可能將每個需求都實現,而是采取一種簡單完成架構流程的辦法,使用最簡單的需求將整個架構都簡單的完成一遍(加入人工干預),以檢驗各個技術環節是否能協調配合工作(非常優秀先進的兩種技術有時無法在一起工作),同時也可以探知技術的深淺,掌握項目中的技術難易點。這個過程完成后,我們就對設計方案做出上面的重大修改,豐富完善了設計方案。

設計模式是支撐架構的重要組件

架構設計也類似一種工作流,它是動態的,這點不象建筑設計那樣,一開始就能完全確定,架構設計伴隨著整個項目的進行過程之中,有兩種具體操作保證架構設計的正確完成,那就是設計模式(靜態)和工程項目方法(RUP或XP 動態的)。

設計模式是支撐架構的一種重要組件,這與建筑有很相象的地方,一個建筑物建立設計需要建筑架構設計,在具體施工中,有很多建筑方面的規則和模式。

我們從J2EE藍圖模式分類http://java.sun.com/blueprints/patterns/catalog.html中就可以很清楚的看到J2EE這樣一個框架軟件的架構與設計模式的關系。

架構設計是骨架,設計模式就是肉

這樣,一個比較豐富的設計方案可以交由程序員進一步完成了,載輔助以適當的工程方法,這樣就可保證項目的架構設計能正確快速的完成。

時刻牢記架構設計的目標

由于架構設計是在動態中完成的,因此在把握架構設計的目標上就很重要,因此在整個項目過程中,甚至每一步我們都必須牢記我們架構設計的總體目標,可以概括下面幾點:

1. 最大化的重用:這個重用包括組件重用 和設計模式使用等多個方面。

比如,我們項目中有用戶注冊和用戶權限系統驗證,這其實是個通用課題,每個項目只是有其內容和一些細微的差別,如果我們之前有這方面成功研發經驗,可以直接重用,如果沒有,那么我們就要進行這個子項目的研發,在研發過程中,不能僅僅看到這個項目的需求,也要以架構的概念去完成這個可以稱為組件的子項目。

2. 盡可能的簡單明了:我們解決問題的總方向是將復雜問題簡單化,其實這也是中間件或多層體系技術的根本目標。但是在具體實施設計過程中,我們可能會將簡單問題復雜化,特別是設計模式的運用上很容易范這個錯誤,因此如何盡可能的做到設計的簡單明了是不容易的。

我認為落實到每個類的具體實現上要真正能體現系統事物的本質特征,因為事物的本質特征只有一個,你的代碼越接近它,表示你的設計就是簡單明了,越簡單明了,你的系統就越可靠。更多情況是,一個類并不能反應事物本質,需要多個類的組合協調,那么能夠正確使用合適的設計模式就稱為重中之重。

我們看一個具備好的架構設計的系統代碼時,基本看到的都是設計模式,寵物店(pet store)就是這樣的例子。或者可以這樣說,一個好的架構設計基本是由簡單明了的多個設計模式完成的。

3. 最靈活的拓展性:架構設計要具備靈活性 拓展性,這樣,用戶可以在你的架構上進行二次開發或更加具體的開發。

要具備靈活的拓展性,就要站在理論的高度去進行架構設計,比如現在工作流概念逐步流行,因為我們具體很多實踐項目中都有工作流的影子,工作流中有一個樹形結構權限設定的概念就對很多領域比較通用。

樹形結構是組織信息的基本形式,我們現在看到的網站或者ERP前臺都是以樹形菜單來組織功能的,那么我們在進行架構設計時,就可以將樹形結構和功能分開設計,他們之間聯系可以通過樹形結構的節點link在一起,就象我們可以在圣誕樹的樹枝上掛各種小禮品一樣,這些小禮品就是我們要實現的各種功能。

有了這個概念,通常比較難實現的用戶級別權限控制也有了思路,將具體用戶或組也是和樹形結構的節點link在一起,這樣就間接實現了用戶對相應功能的權限控制,有了這樣的基本設計方案的架構無疑具備很靈活的拓展性。?

如何設計架構?

2007-07-19 11:11 來源: 作者: 網友評論 0 條 瀏覽次數 26

Part 1 層

??? 層(layer)這個概念在計算機領域是非常了不得的一個概念。計算機本身就體現了一種層的概念:系統調用層、設備驅動層、操作系統層、CPU指令集。每個層都負責自己的職責。網絡同樣也是層的概念,最著名的TCP/IP的七層協議。

??? 層到了軟件領域也一樣好用。為什么呢?我們看看使用層技術有什么好處:

??? ● 你使用層,但是不需要去了解層的實現細節。
??? ● 可以使用另一種技術來改變基礎的層,而不會影響上面的層的應用。
??? ● 可以減少不同層之間的依賴。
??? ● 容易制定出層標準。
??? ● 底下的層可以用來建立頂上的層的多項服務。

??? 當然,層也有弱點:

??? ● 層不可能封裝所有的功能,一旦有功能變動,勢必要波及所有的層。
??? ● 效率降低。

當然,層最難的一個問題還是各個層都有些什么,以及要承擔何種責任。

典型的三層結構

??? 三層結構估計大家都很熟悉了。就是表示(presentation)層, 領域(domain)層, 以及基礎架構(infrastructure)層。

??? 表示層邏輯主要處理用戶和軟件的交互。現在最流行的莫過于視窗圖形界面(wimp)和基于html的界面了。表示層的主要職責就是為用戶提供信息,以及把用戶的指令翻譯。傳送給業務層和基礎架構層。

??? 基礎架構層邏輯包括處理和其他系統的通信,代表系統執行任務。例如數據庫系統交互,和其他應用系統的交互等。大多數的信息系統,這個層的最大的邏輯就是存儲持久數據。

??? 還有一個就是領域層邏輯,有時也被叫做業務邏輯。它包括輸入和存儲數據的計算。驗證表示層來的數據,根據表示層的指令指派一個基礎架構層邏輯。

??? 領域邏輯中,人們總是搞不清楚什么事領域邏輯,什么是其它邏輯。例如,一個銷售系統中有這樣一個邏輯:如果本月銷售量比上個月增長10%,就要用紅色標記。要實現這個功能,你可能會把邏輯放在表示層中,比較兩個月的數字,如果超出10%,就標記為紅色。

??? 這樣做,你就把領域邏輯放到了表示層中了。要分離這兩個層,你應該現在領域層中提供一個方法,用來比較銷售數字的增長。這個方法比較兩個月的數字,并返回boolean類型。表示層則簡單的調用該方法,如果返回true,則標記為紅色。

例子

??? 層技術不存在說永恒的技巧。如何使用都要看具體的情況才能夠決定,下面我就列出了三個例子:

??? 例子1:一個電子商務系統。要求能夠同時處理大量用戶的請求,用戶的范圍遍及全球,而且數字還在不斷增長。但是領域邏輯很簡單,無非是訂單的處理,以及和庫存系統的連接部分。這就要求我們1、表示層要友好,能夠適應最廣泛的用戶,因此采用html技術;2、支持分布式的處理,以勝任同時幾千的訪問;3、考慮未來的升級。

??? 例子2:一個租借系統。系統的用戶少的多,但是領域邏輯很復雜。這就要求我們制作一個領域邏輯非常復雜的系統,另外,還要給他們的用戶提供一個方便的輸入界面。這樣,wimp是一個不錯的選擇。

??? 例子3:簡單的系統。非常簡單,用戶少、邏輯少。但是也不是沒有問題,簡單意味著要快速交付,并且還要充分考慮日后的升級。因為需求在不斷的增加之中。

何時分層

??? 這樣的三個例子,就要求我們不能夠一概而論的解決問題,而是應該針對問題的具體情況制定具體的解決方法。這三個例子比較典型。

??? 第二個例子中,可能需要嚴格的分成三個層次,而且可能還要加上另外的中介(mediating)層。例3則不需要,如果你要做的僅是查看數據,那僅需要幾個server頁面來放置所有的邏輯就可以了。

??? 我一般會把表示層和領域層/基礎架構層分開。除非領域層/基礎架構層非常的簡單,而我又可以使用工具來輕易的綁定這些層。這種兩層架構的最好的例子就是在VB、PB的環境中,很容易就可以構建出一個基于SQL數據庫的windows界面的系統。這樣的表示層和基礎架構層非常的一致,但是一旦驗證和計算變得復雜起來,這種方式就存在先天缺陷了。

??? 很多時候,領域層和基礎架構層看起來非常類似,這時候,其實是可以把它們放在一起的。可是,當領域層的業務邏輯和基礎架構層的組織方式開始不同的時候,你就需要分開二者。

更多的層模式

??? 三層的架構是最為通用的,尤其是對IS系統。其它的架構也有,但是并不適用于任何情況。

??? 第一種是Brown model [Brown et al]。它有五個層:表示層(Presentation),控制/中介層(Controller/Mediator),領域層(Domain), 數據映射層(Data Mapping), 和數據源層(Data Source)。它其實就是在三層架構種增加了兩個中間層。控制/中介層位于表示層和領域層之間,數據映射層位于領域層和基礎架構層之間。

??? 表示層和領域層的中介層,我們通常稱之為表示-領域中介層,是一個常用的分層方法,通常針對一些非可視的控件。例如為特定的表示層組織信息格式,在不同的窗口間導航,處理交易邊界,提供Server的facade接口(具體實現原理見設計模式)。最大的危險就是,一些領域邏輯被放到這個層里,影響到其它的表示層。

??? 我常常發現把行為分配給表示層是有好處的。這可以簡化問題。但表示層模型會比較復雜,所以,把這些行為放到非可視化的對象中,并提取出一個表示-領域中介層還是值得的。

??? Brown ISA
??? 表示層 表示層
?? 控制/中介層 表示-領域中介層
??? 領域層 領域層
??? 數據映射層 數據庫交互模式中的Database Mapper
??? 數據源層 基礎架構層

??? 領域層和基礎架構層之間的中介層屬于本書中提到的Database Mapper模式,是三種領域層到數據連接的辦法之一。和表示-領域中介層一眼,有時候有用,但不是所有時候都有用。

??? 還有一個好的分層架構是J2EE的架構,這方面的討論可以見『J2EE核心模式』一書。他的分層是客戶層(Client),表示層(Presentation),業務層(Business ),整合層(Integration),資源層(Resource)。差別如下圖:

??? J2EE核心 ISA
??? 客戶層 運行在客戶機上的表示層
?? 表示層 運行在服務器上的表示層
??? 業務層 領域層
??? 整合層 基礎架構層
??? 資源層 基礎架構層通信的外部數據

??? 微軟的DNA架構定義了三個層:表示層(presentation),業務層(business),和數據存儲層(data access),這和我的架構相似,但是在數據的傳遞方式上還有很大的不同。在微軟的DNA中,各層的操作都基于數據存儲層傳出的SQL查詢結果集。這樣的話,實際上是增加了表示層和業務層同數據存儲層之間的耦合度。

??? DNA的記錄集在層之間的動作類似于Data Transfer Object。
????


Part 2 組織領域邏輯

??? 要組織基于層的系統,首要的是如何組織領域邏輯。領域邏輯的組織有好幾種模式。但其中最重要的莫過于兩種方法:Transation Script和Domain Model。選定了其中的一種,其它的都容易決定。不過,這兩者之間并沒有一條明顯的分界線。所以如何選取也是門大學問。一般來說,我們認為領域邏輯比較復雜的系統可以采用Domain Model。

??? Transation Script就是對表示層用戶輸入的處理程序。包括驗證和計算,存儲,調用其它系統的操作,把數據回傳給表示層。用戶的一個動作表示一個程序,這個程序可以是script,也可以是transation,也可以是幾個子程序。在例子1中,檢驗,在購物車中增加一本書,顯示遞送狀態,都可以是一個Transation Script。

??? Domain Model是要建立對應領域名詞的模型,例如例1中的書、購物車等。檢驗、計算等處理都放到領域模型中。

??? Transation Script屬于結構性思維,Domain Model屬于OO思維。Domain Model比較難使用,一旦習慣,你能夠組織更復雜的邏輯,你的思想會更OO。到時候,即使是小的系統,你也會自然的使用Domain Model了。

??? 但如何抉擇呢?如果邏輯復雜,那肯定用Domain Model:如果只需要存取數據庫,那Transation Script會好一些。但是需求是在不斷進化的,你很難保證以后的需求還會如此簡單。如果你的團隊不善于使用Domain Model,那你需要權衡一下投入產出比。另外,即使是Transation Script,也可以做到把邏輯和基礎架構分開,你可以使用Gateway。

??? 對例2,毫無疑問要使用Domain Model。對例1就需要權衡了。而對于例3,你很難說它將來會不會像例2那樣,你現在可以使用Transation Script,但未來你可能要使用Domain Model。所以說,架構的決策是至關緊要的。

??? 除了這兩種模式,還有其它中庸的模式。Use Case Controller就是處于兩者之間。只有和單個的用例相關的業務邏輯才放到對象中。所以大致上他們還是在使用Transation Script,而Domain Model只是Database Gateway的一組集合而已。我不太用這種模式。

??? Table Module是另一個中庸模式。很多的GUI環境依托于SQL查詢的返回結果。你可以建立內存中的對象,來把GUI和數據庫分開來。為每個表寫一個模塊,因此每一行都需要關鍵字變量來識別每一個實例。

??? Table Module適用于很多的組件構建于一個通用關系型數據庫之上,而且領域邏輯不太復雜的情況。Microsoft COM 環境,以及它的帶ADO.NET的.NET環境都適合使用這種模式。而對于Java,就不太適用了。

??? 領域邏輯的一個問題是領域對象非常的臃腫。因為對象的行為太多了,類也就太大了。它必須是一個超集。這就要考慮哪些行為是通用的,哪些不是,可以由其它的類來處理,可能是Use Case Controller,也可能是表示層。

??? 還有一個問題,復制。他會導致復雜和不一致。這比臃腫的危害更大。所以,寧可臃腫,也不要復制。等到臃腫為害時再處理它吧。

選擇一個地方運行領域邏輯

??? 我們的精力集中在邏輯層上。領域邏輯要么運行在Client上,要么運行在Server上。

??? 比較簡單的做法是全部集中在Server上。這樣你需要使用html的前端以及web server。這樣做的好處是升級和維護都非常的簡單,你也不用考慮桌面平臺和Server的同步問題,也不用考慮桌面平臺的其它軟件的兼容問題。

??? 運行在Client適合于要求快速反應和沒有聯網的情況。在Server端的邏輯,用戶的一個再小的請求,也需要信息從Client到Server繞一圈。反應的速度必然慢。再說,網絡的覆蓋程度也不是說達到了100%。

??? 對于各個層來說,又是怎么樣的呢?

??? 基礎架構層:一般都是在Server啦,不過有時候也會把數據復制到合適的高性能桌面機,但這是就要考慮同步的問題了。

??? 表示層在何處運行取決于用戶界面的設計。一個Windows界面只能在Client運行。而一個Web界面就是在Server運行。也有特別的例子,在桌面機上運行web server的,例如X Server。但這種情況少的多。

??? 在例1中,沒有更多的選擇了,只能選在Server端。因此你的每一個bit都會繞一個大圈子。為了提高效率,盡量使用一些純html腳本。

??? 人們選用Windows界面的原因主要就是需要執行一些非常復雜的任務,需要一個合適的應用程序,而web GUI則無法勝任。這就是例2的做法。不過,人們應該會漸漸適應web GUI,而web GUI的功能也會越來越強大。

??? 剩下的是領域邏輯。你可以全部放在Server,也可以全部放在Client,或是兩邊都放。

??? 如果是在Client端,你可以考慮全部邏輯都放在Client端,這樣至少保證所有的邏輯都在一個地方。而把web server移至Client,是可以解決沒有聯網的問題,但對反應時間不會有多大的幫助。你還是可以把邏輯和表示層分離開來。當然,你需要額外的升級和維護的工作。

??? 在Client和Server端都具有邏輯并不是一個好的處理辦法。但是對于那些僅有一些領域邏輯的情況是適用的。有一個小竅門,把那些和系統的其它部分沒有聯系的邏輯封裝起來。

領域邏輯的接口

??? 你的Server上有一些領域邏輯,要和Client通信,你應該有什么樣的接口呢?要么是一個http接口,要么是一個OO接口。

??? http接口適用于web browser,就是說你要選擇一個html的表示層。最近的新技術就是web service,通過基于http、特別是XML進行通信。XML有幾個好處:通信量大,結構好,僅需一次的回路。這樣遠程調用的的開銷就小了。同時,XML還是一個標準,支持平臺異構。XML又是基于文本的,能夠通過防火墻。

??? 雖然XML有那么多的好處,不過一個OO的接口還是有它的價值的。hhtp的接口不明顯,不容易看清楚數據是如何處理的。而OO的接口的方法帶有變量和名字,容易看出處理的過程。當然,它無法通過防火墻,但可以提供安全和事務之類的控制。

??? 最好的還是取二者所長。OO接口在下,http接口在上。但這樣做就會使得實現機制非常的復雜。

?

Part 3 組織web Server

??? 很多使用html方式的人,并不能真正理解這種方式的優點。我們有各種各樣好用的工具,但是卻搞到讓程序難以維護。

??? 在web server上組織程序的方式大致可以分為兩種:腳本和server page。

??? 腳本方式就是一個程序,用函數和方法來處理http調用。例如CGI腳本和java servlet。它和普通的程序并沒有什么兩樣。它從web頁面上獲得html string形態的數據,有時候還要做一些表達式匹配,這正是perl能夠成為CGI腳本的常用語言的原因。而java servelet則是把這種分析留給程序員,但它允許程序員通過關鍵字接口來訪問信息,這樣就會少一些表達式的判斷。這種格式的web server輸出是另一種html string,稱為response,可以通過流數據來操作。

??? 糟糕的是流數據是非常麻煩的,因此就導致了server page的產生,例如PHP,ASP,JSP。

??? server page的方式適合回應(response)的處理比較簡單的情況。例如“顯示歌曲的明細”,但是你的決策取決于輸入的時候,就會比較雜亂。例如“通俗和搖滾的顯示格式不同”。

??? 腳步擅長于處理用戶交互,server page擅長于處理格式化回應信息。所以很自然的就會采用腳本處理請求的交互,使用server page處理回應的格式化。這其實就是著名的MVC(Model View Controller)模式中的view/controller的處理。

web server端的MVC工作流程示意圖


??? 應用Model View Controller模式首要的一點就是模型要和web服務完全分離開來。使用Transaction Script或Domain Model模式來封裝處理流程。

??? 接下來,我們就把剩余的模式歸入兩類模式中:屬于Controller的模式,以及屬于View的模式。

View模式

??? View這邊有三種模式:Transform View,Template View和Two Step View。Transform View和Template View的處理只有一步,將領域數據轉換為html。Two Step View要經過兩步的處理,第一步把領域數據轉換為邏輯表示形式,第二步把邏輯表示轉換為html。

??? 兩步處理的好處是可以將邏輯集中于一處,如果只有一步,變化發生時,你就需要修改每一個屏幕。但這需要你有一個很好的邏輯屏幕結構。如果一個web應用有很多的前端用戶時,兩步處理就特別的好用。例如航空訂票系統。使用不同的第二步處理,就可以獲得不同的邏輯屏幕。

??? 使用單步方法有兩個可選的模式:Template View,Transform View。Template View其時就是把代碼嵌入到html頁面中,就像現在的server page技術,如ASP,PHP,JSP。這種模式靈活,強大,但顯得雜亂無章。如果你能夠把邏輯程序邏輯在頁面結構之外進行很好的組織,這種模式還是有它的優點的。

??? Transform View使用翻譯方式。例如XSLT。如果你的領域數據是用XML處理的,那這種模式就特別的好用。

Controller模式

??? Controller有兩種模式。一般我們會根據動作來決定一項控制。動作可能是一個按鈕或鏈接。所這種模式就是Action Controller模式。

??? Front Controller更進一步,它把http請求的處理和處理邏輯分離開來。一般是只有一個web handle來處理所有的請求。你的所有的http請求的處理都由一個對象來負責。你改變動作結構的影響就會降到最小



架構設計的方法學

約公元前25年,古羅馬建筑師維特魯威說:“理想的建筑師應該既是文學家又是數字家,他還應通曉歷史,熱衷于哲學研究,精通音樂,懂得醫藥知識,具有法學造詣,深諳天文學及天文計算。”(好難哪,軟件構架設計師的要求呢?大家好好想想吧。)
??本文目錄
??一、與構架有關的幾個基本概念;
??二、構架設計應考慮的因素概攬;
??三、程序的運行時結構方面的考慮;
??四、源代碼的組織結構方面的考慮;
??五、寫系統構架設計文檔應考慮的問題
??六、結語
??一、與構架有關的幾個基本概念:
? 1、模塊(module):一組完成指定功能的語句,包括:輸入、輸出、邏輯處理功能、內部信息、運行環境(與功能對應但不是一對一關系)。
??2、組件(component):系統中相當重要的、幾乎是獨立的可替換部分,它在明確定義的構架環境中實現確切的功能。
??3、模式(pattern):指經過驗證,至少適用于一種實用環境(更多時候是好幾種環境)的解決方案模板(用于結構和行為。在?UML中:模式由參數化的協作來表示,但?UML?不直接對模式的其他方面(如使用結果列表、使用示例等,它們可由文本來表示)進行建模。存在各種范圍和抽象程度的模式,例如,構架模式、分析模式、設計模式和代碼模式或實施模式。模式將可以幫助我們抓住重點。構架也是存在模式的。比如,對于系統結構設計,我們使用層模式;對于分布式系統,我們使用代理模式(通過使用代理來替代實際的對象,使程序能夠控制對該對象的訪問);對于交互系統,我們使用MVC(M模型(對象)/V視圖(輸出管理)/C控制器(輸入處理))模式。模式是針對特定問題的解,因此,我們也可以針對需求的特點采用相應的模式來設計構架。
??4、構架模式(architectural pattern):表示軟件系統的基本結構組織方案。它提供了一組預定義的子系統、指定它們的職責,并且包括用于組織其間關系的規則和指導。
??5、層(layer):對模型中同一抽象層次上的包進行分組的一種特定方式。通過分層,從邏輯上將子系統劃分成許多集合,而層間關系的形成要遵循一定的規則。通過分層,可以限制子系統間的依賴關系,使系統以更松散的方式耦合,從而更易于維護。(層是對構架的橫向劃分,分區是對構架的縱向劃分)。
??6、系統分層的幾種常用方法:
??1) 常用三層服務:用戶層、業務邏輯層、數據層;
??2) 多層結構的技術組成模型:表現層、中間層、數據層;
??3) 網絡系統常用三層結構:核心層、匯聚層和接入層;
??4)?RUP典型分層方法:應用層、專業業務層、中間件層、系統軟件層;
??5) 基于Java的B/S模式系統結構:瀏覽器端、服務器端、請求接收層、請求處理層;
??6) 某六層結構:功能層(用戶界面)、模塊層、組裝層(軟件總線)、服務層(數據處理)、數據層、核心層;
??7、構架(Architecture,愿意為建筑學設計和建筑物建造的藝術與科學):?在RUP中的定義:軟件系統的構架(在某一給定點)是指系統重要構件的組織或結構,這些重要構件通過接口與不斷減小的構件與接口所組成的構件進行交互;《軟件構架實踐》中的定義:某個軟件或者計算系統的軟件構架即組成該系統的一個或者多個結構,他們組成軟件的各個部分,形成這些組件的外部可見屬性及相互間的聯系;IEEE 1471-2000中的定義:the fundamental organization of a system emboided in its components,their relationships to each other,and to the enviroment and the principles guiding its design and evolution,構架是系統在其所處環境中的最高層次的概念。軟件系統的構架是通過接口交互的重要構件(在特定時間點)的組織或結構,這些構件又由一些更小的構件和接口組成。(“構架”可以作為名詞,也可作為動詞,作為動詞的“構架”相當于“構架設計”)
??8、構架的描述方式:“4+1”視圖(用例視圖、設計視圖、實現視圖、過程視圖、配置視圖)是一個被廣為使用的構架描述的模型;RUP過程的構架描述模板在“4+1”視圖的基礎上增加了可選的數據視圖(從永久性數據存儲方面來對系統進行說明);HP公司的軟件描述模板也是基于“4+1”視圖。
??9、結構:軟件構架是多種結構的體現,結構是系統構架從不同角度觀察所產生的視圖。就像建筑物的結構會隨著觀察動機和出發點的不同而有多種含義一樣,軟件構架也表現為多種結構。常見的軟件結構有:模塊結構、邏輯或概念結構、進程或協調結構、物理結構、使用結構、調用結構、數據流、控制流、類結構等等。
??二、構架設計應考慮的因素概攬:
??模塊構架設計可以從程序的運行時結構和源代碼的組織結構方面考慮。
??1、程序的運行時結構方面的考慮:
??1) 需求的符合性:正確性、完整性;功能性需求、非功能性需求;
??2) 總體性能(內存管理、數據庫組織和內容、非數據庫信息、任務并行性、網絡多人操作、關鍵算法、與網絡、硬件和其他系統接口對性能的影響);
??3) 運行可管理性:便于控制系統運行、監視系統狀態、錯誤處理;模塊間通信的簡單性;與可維護性不同;
??4) 與其他系統接口兼容性;
??5) 與網絡、硬件接口兼容性及性能;
??6) 系統安全性;
??7) 系統可靠性;
??8) 業務流程的可調整性;
??9) 業務信息的可調整性
??10) 使用方便性
??11) 構架樣式的一致性
??注:運行時負載均衡可以從系統性能、系統可靠性方面考慮。
??2、源代碼的組織結構方面的考慮:
??1) 開發可管理性:便于人員分工(模塊獨立性、開發工作的負載均衡、進度安排優化、預防人員流動對開發的影響)、利于配置管理、大小的合理性與適度復雜性;
??2) 可維護性:與運行可管理性不同;
??3) 可擴充性:系統方案的升級、擴容、擴充性能;
??4) 可移植性:不同客戶端、應用服務器、數據庫管理系統;
??5) 需求的符合性(源代碼的組織結構方面的考慮)。

三、程序的運行時結構方面的考慮:
??1、 需求的符合性:正確性、完整性;功能性需求、非功能性需求
??軟件項目最主要的目標是滿足客戶需求。在進行構架設計的時候,大家考慮更多的是使用哪個運行平臺、編成語言、開發環境、數據庫管理系統等問題,對于和客戶需求相關的問題考慮不足、不夠系統。如果無論怎么好的構架都無法滿足客戶明確的某個功能性需求或非功能性需求,就應該與客戶協調在項目范圍和需求規格說明書中刪除這一需求。否則,架構設計應以滿足客戶所有明確需求為最基本目標,盡量滿足其隱含的需求。(客戶的非功能性需求可能包括接口、系統安全性、可靠性、移植性、擴展性等等,在其他小節中細述)
??一般來說,功能需求決定業務構架、非功能需求決定技術構架,變化案例決定構架的范圍。需求方面的知識告訴我們,功能需求定義了軟件能夠做些什么。我們需要根據業務上的需求來設計業務構架,以使得未來的軟件能夠滿足客戶的需要。非功能需求定義了一些性能、效率上的一些約束、規則。而我們的技術構架要能夠滿足這些約束和規則。變化案例是對未來可能發生的變化的一個估計,結合功能需求和非功能需求,我們就可以確定一個需求的范圍,進而確定一個構架的范圍。(此段From林星)
??這里講一個前幾年因客戶某些需求錯誤造成構架設計問題而引起系統性能和可靠性問題的小小的例子:此系統的需求本身是比較簡單的,就是將某城市的某業務的全部歷史檔案卡片掃描存儲起來,以便可以按照姓名進行查詢。需求階段客戶說卡片大約有20萬張,需求調研者出于對客戶的信任沒有對數據的總量進行查證。由于是中小型數據量,并且今后數據不會增加,經過計算20萬張卡片總體容量之后,決定使用一種可以單機使用也可以聯網的中小型數據庫管理系統。等到系統完成開始錄入數據時,才發現數據至少有60萬,這樣使用那種中小型數據庫管理系統不但會造成系統性能的問題,而且其可靠性是非常脆弱的,不得不對系統進行重新設計。從這個小小的教訓可以看出,需求階段不僅對客戶的功能需求要調查清楚,對于一些隱含非功能需求的一些數據也應當調查清楚,并作為構架設計的依據。
??對于功能需求的正確性,在構架設計文檔中可能不好驗證(需要人工、費力)。對于功能需求完整性,就應當使用需求功能與對應模塊對照表來跟蹤追溯。對于非功能需求正確性和完整性,可以使用需求非功能與對應設計策略對照表來跟蹤追溯評估。
??“軟件設計工作只有基于用戶需求,立足于可行的技術才有可能成功。”
??2、 總體性能
??性能其實也是客戶需求的一部分,當然可能是明確的,也有很多是隱含的,這里把它單獨列出來在說明一次。性能是設計方案的重要標準,性能應考慮的不是單臺客戶端的性能,而是應該考慮系統總的綜合性能;
??性能設計應從以下幾個方面考慮:內存管理、數據庫組織和內容、非數據庫信息、任務并行性、網絡多人操作、關鍵算法、與網絡、硬件和其他系統接口對性能的影響;
幾點提示:算法優化及負載均衡是性能優化的方向。經常要調用的模塊要特別注意優化。占用內存較多的變量在不用時要及時清理掉。需要下載的網頁主題文件過大時應當分解為若干部分,讓用戶先把主要部分顯示出來。
??3、 運行可管理性
??系統的構架設計應當為了使系統可以預測系統故障,防患于未然。現在的系統正逐步向復雜化、大型化發展,單靠一個人或幾個人來管理已顯得力不從心,況且對于某些突發事件的響應,人的反應明顯不夠。因此通過合理的系統構架規劃系統運行資源,便于控制系統運行、監視系統狀態、進行有效的錯誤處理;為了實現上述目標,模塊間通信應當盡可能簡單,同時建立合理詳盡的系統運行日志,系統通過自動審計運行日志,了解系統運行狀態、進行有效的錯誤處理;(運行可管理性與可���護性不同)
??4、 與其他系統接口兼容性(解釋略)
??5、 與網絡、硬件接口兼容性及性能(解釋略)
??6、 系統安全性
??隨著計算機應用的不斷深入和擴大,涉及的部門和信息也越來越多,其中有大量保密信息在網絡上傳輸,所以對系統安全性的考慮已經成為系統設計的關鍵,需要從各個方面和角度加以考慮,來保證數據資料的絕對安全。
??7、 系統可靠性
??系統的可靠性是現代信息系統應具有的重要特征,由于人們日常的工作對系統依賴程度越來越多,因此系統的必須可靠。系統構架設計可考慮系統的冗余度,盡可能地避免單點故障。系統可靠性是系統在給定的時間間隔及給定的環境條件下,按設計要求,成功地運行程序的概率。成功地運行不僅要保證系統能正確地運行,滿足功能需求,還要求當系統出現意外故障時能夠盡快恢復正常運行,數據不受破壞。
??8、 業務流程的可調整性
??應當考慮客戶業務流程可能出現的變化,所以在系統構架設計時要盡量排除業務流程的制約,即把流程中的各項業務結點工作作為獨立的對象,設計成獨立的模塊或組件,充分考慮他們與其他各種業務對象模塊或組件的接口,在流程之間通過業務對象模塊的相互調用實現各種業務,這樣,在業務流程發生有限的變化時(每個業務模塊本身的業務邏輯沒有變的情況下),就能夠比較方便地修改系統程序模塊或組件間的調用關系而實現新的需求。如果這種調用關系被設計成存儲在配置庫的數據字典里,則連程序代碼都不用修改,只需修改數據字典里的模塊或組件調用規則即可。
??9、 業務信息的可調整性
??應當考慮客戶業務信息可能出現的變化,所以在系統構架設計時必須盡可能減少因為業務信息的調整對于代碼模塊的影響范圍。
??10、 使用方便性
??使用方便性是不須提及的必然的需求,而使用方便性與系統構架是密切相關的。WinCE(1.0)的失敗和后來改進版本的成功就說明了這個問題。WinCE(1.0)有太多層次的視窗和菜單,而用戶則更喜歡簡單的界面和快捷的操作。失敗了應當及時糾正,但最好不要等到失敗了再來糾正,這樣會浪費巨大的財力物力,所以在系統構架階段最好能將需要考慮的因素都考慮到。當然使用方便性必須與系統安全性協調平衡統一,使用方便性也必須與業務流程的可調整性和業務信息的可調整性協調平衡統一。“滿足用戶的需求,便于用戶使用,同時又使得操作流程盡可能簡單。這就是設計之本。”
??11、構架樣式的一致性
??軟件系統的構架樣式有些類似于建筑樣式(如中國式、哥特式、希臘復古式)。軟件構架樣式可分為數據流構架樣式、調用返回構架樣式、獨立組件構架樣式、以數據為中心的構架樣式和虛擬機構架樣式,每一種樣式還可以分為若干子樣式。構架樣式的一致性并不是要求一個軟件系統只能采用一種樣式,就像建筑樣式可以是中西結合的,軟件系統也可以有異質構架樣式(分為局部異質、層次異質、并行異質),即多種樣式的綜合,但這樣的綜合應該考慮其某些方面的一致性和協調性。每一種樣式都有其使用的時機,應當根據系統最強調的質量屬性來選擇。?
??四、源代碼的組織結構方面的考慮:
??1、 開發可管理性
??便于人員分工(模塊獨立性、開發工作的負載均衡、進度安排優化、預防人員流動對開發的影響:一個好的構架同時應有助于減少項目組的壓力和緊張,提高軟件開發效率)、利于配置管理、大小的合理性、適度復雜性;
??1)便于人員分工-模塊獨立性、層次性
??模塊獨立性、層次性是為了保證項目開發成員工作之間的相對獨立性,模塊聯結方式應該是縱向而不是橫向,?模塊之間應該是樹狀結構而不是網狀結構或交叉結構,這樣就可以把開發人員之間的通信、模塊開發制約關系減到最少。同時模塊獨立性也比較利于配置管理工作的進行。現在有越來越多的的軟件開發是在異地進行,一個開發組的成員可能在不同城市甚至在不同國家,因此便于異地開發的人員分工與配置管理的源代碼組織結構是非常必要的。
??2)便于人員分工-開發工作的負載均衡
??不僅僅是開發出來的軟件系統需要負載均衡,在開發過程中開發小組各成員之間工作任務的負載均衡也是非重要的。所謂工作任務的負載均衡就是通過合理的任務劃分按照開發人員特點進行分配任務,盡量讓項目組中的每個人每段時間都有用武之地。這就需要在構架設計時應當充分考慮項目組手頭的人力資源,在實現客戶需求的基礎上實現開發工作的負載均衡,以提高整體開發效率。
??3)便于人員分工-進度安排優化;
??進度安排優化的前提是模塊獨立性并搞清楚模塊開發的先后制約關系。利用工作分解結構對所有程序編碼工作進行分解,得到每一項工作的輸入、輸出、所需資源、持續時間、前期應完成的工作、完成后可以進行的工作。然后預估各模塊需要時間,分析各模塊的并行與串行(順序制約),繪制出網絡圖,找出影響整體進度的關鍵模塊,算出關鍵路徑,最后對網絡圖進行調整,以使進度安排最優化。
??有個家喻戶曉的智力題叫烤肉片策略:約翰遜家戶外有一個可以同時烤兩塊肉片的烤肉架,烤每塊肉片的每一面需要10分鐘,現要烤三塊肉片給饑腸轆轆急不可耐的一家三口。問題是怎樣才能在最短的時間內烤完三片肉。一般的做法花20分鐘先烤完前兩片,再花20分鐘烤完第三片。有一種更好的方法可以節省10分鐘,大家想想。
??4)便于人員分工-預防員工人員流動對開發的影響
??人員流動在軟件行業是司空見慣的事情,已經是一個常見的風險。作為對這一風險的有效的防范對策之一,可以在構架設計中考慮到并預防員工人員流動對開發的影響。主要的思路還是在模塊的獨立性上(追求高內聚低耦合),組件化是目前流行的趨勢。
??5)利于配置管理(獨立性、層次性)
??利于配置管理與利于人員分工有一定的聯系。除了邏輯上的模塊組件要利于人員分工外,物理上的源代碼層次結構、目錄結構、各模塊所處源代碼文件的部署也應當利于人員分工和配置管理。(盡管現在配置管理工具有較強大的功能,但一個清楚的源碼分割和模塊分割是非常有好處的)。
??6)大小的合理性與適度復雜性
??大小的合理性與適度復雜性可以使開發工作的負載均衡,便于進度的安排,也可以使系統在運行時減少不必要的內存資源浪費。對于代碼的可閱讀性和系統的可維護性也有一定的好處。另外,過大的模塊常常是系統分解不充分,而過小的模塊有可能降低模塊的獨立性,造成系統接口的復雜。
??2、 可維護性
??便于在系統出現故障時及時方便地找到產生故障的原因和源代碼位置,并能方便地進行局部修改、切割;(可維護性與運行可管理性不同)
??3、 可擴充性:系統方案的升級、擴容、擴充性能
??系統在建成后會有一段很長的運行周期,在該周期內,應用在不斷增加,應用的層次在不斷升級,因此采用的構架設計等方案因充分考慮升級、擴容、擴充的可行性和便利
??4、 可移植性
??不同客戶端、應用服務器、數據庫管理系統:如果潛在的客戶使用的客戶端可能使用不同的操作系統或瀏覽器,其可移植性必須考慮客戶端程序的可移植性,或盡量不使業務邏輯放在客戶端;數據處理的業務邏輯放在數據庫管理系統中會有較好的性能,但如果客戶群中不能確定使用的是同一種數據庫管理系統,則業務邏輯就不能數據庫管理系統中;
達到可移植性一定要注重標準化和開放性:只有廣泛采用遵循國際標準,開發出開放性強的產品,才可以保證各種類型的系統的充分互聯,從而使產品更具有市場競爭力,也為未來的系統移植和升級擴展提供了基礎。
??5、 需求的符合性
??從源代碼的組織結構看需求的符合型主要考慮針對用戶需求可能的變化的軟件代碼及構架的最小冗余(同時又要使得系統具有一定的可擴展性)。
??五、寫系統構架設計文檔應考慮的問題
??構架工作應該在需求開發完成約80%的時候開始進行,不必等到需求開發全部完成,需要項目經理以具體的判斷來評估此時是否足以開始構建軟件構架。
??給出一致的輪廓:系統概述。一個系統構架需要現有概括的描述,開發人員才能從上千個細節甚至數十個模塊或對象類中建立一致的輪廓。
??構架的目標應該能夠清楚說明系統概念,構架應盡可能簡化,最好的構架文件應該簡單、簡短,清晰而不雜亂,解決方案自然。
??構架應單先定義上層的主要子系統,應該描述各子系統的任務,并提供每個子系統中各模塊或對象類的的初步列表。
??構架應該描述不同子系統間相互通信的方式,而一個良好的構架應該將子系統間的通信關系降到最低。
??成功構架的一個重要特色,在于標明最可能變更的領域,應當列出程序中最可能變更的部分,說明構架的其他部分如何應變。
??復用分析、外購:縮短軟件開發周期、降低成本的有效方案未必是自行開發軟件,可以對現有軟件進行復用或進行外購。應考慮其對構架的影響。
??除了系統組織的問題,構架應重點考慮對于細節全面影響的設計決策,深入這些決策領域:外部軟件接口(兼容性、通信方式、傳遞數據結構)、用戶接口(用戶接口和系統層次劃分)、數據庫組織和內容、非數據庫信息、關鍵算法、內存管理(配置策略)、并行性、安全性、可移植性、網絡多人操作、錯誤處理。
??要保證需求的可追蹤性,即保證每個需求功能都有相應模塊去實現。
??構架不能只依據靜態的系統目標來設計,也應當考慮動態的開發過程,如人力資源的情況,進度要求的情況,開發環境的滿足情況。構架必須支持階段性規劃,應該能夠提供階段性規劃中如何開發與完成的方式。不應該依賴無法獨立運行的子系統構架。將系統各部分的、依賴關系找出來,形成一套開發計劃。
??六、結語
??系統構架設計和千差萬別的具體的開發平臺密切相關,因此在此無法給出通用的解決方案,主要是為了說明哪些因素是需要考慮的。對于每個因素的設計策略和本文未提到的因素需要軟件構架設計師在具體開發實踐中靈活把握。不同因素之間有時是矛盾的,構架設計時需要根據具體情況進行平衡。
?

架構設計中的方法學

架構設計是一種權衡(trade-off)。一個問題總是有多種的解決方案。而我們要確定唯一的架構設計的解決方案,就意味著我們要在不同的矛盾體之間做出一個權衡。我們在設計的過程總是可以看到很多的矛盾體:開放和整合,一致性和特殊化,穩定性和延展性等等。任何一對矛盾體都源于我們對軟件的不同期望。可是,要滿足我們希望軟件穩定運行的要求,就必然會影響我們對軟件易于擴展的期望。我們希望軟件簡單明了,卻增加了我們設計的復雜度。沒有一個軟件能夠滿足所有的要求,因為這些要求之間帶有天生的互斥性。而我們評價架構設計的好壞的依據,就只能是根據不同要求的輕���緩急,在其間做出權衡的合理性。

1.????????目標?
我們希望一個好的架構能夠:?

重用:為了避免重復勞動,為了降低成本,我們希望能夠重用之前的代碼、之前的設計。重用是我們不斷追求的目標之一,但事實上,做到這一點可沒有那么容易。在現實中,人們已經在架構重用上做了很多的工作,工作的成果稱為框架(Framework),比如說Windows的窗口機制、J2EE平臺等。但是在企業商業建模方面,有效的框架還非常的少。?
????透明:有些時候,我們為了提高效率,把實現的細節隱藏起來,僅把客戶需求的接口呈現給客戶。這樣,具體的實現對客戶來說就是透明的。一個具體的例子是我們使用JSP的tag技術來代替JSP的嵌入代碼,因為我們的HTML界面人員更熟悉tag的方式。?
延展:我們對延展的渴求源于需求的易變。因此我們需要架構具有一定的延展性,以適應未來可能的變化。可是,如上所說,延展性和穩定性,延展性和簡單性都是矛盾的。因此我們需要權衡我們的投入/產出比。以設計出具有適當和延展性的架構。?
簡明:一個復雜的架構不論是測試還是維護都是困難的。我們希望架構能夠在滿足目的的情況下盡可能的簡單明了。但是簡單明了的含義究竟是什么好像并沒有一個明確的定義。使用模式能夠使設計變得簡單,但這是建立在我熟悉設計模式的基礎上。對于一個并不懂設計模式的人,他會認為這個架構很復雜。對于這種情況,我只能對他說,去看看設計模式。?
?????高效:不論是什么系統,我們都希望架構是高效的。這一點對于一些特定的系統來說尤其重要。例如實時系統、高訪問量的網站。這些值的是技術上的高效,有時候我們指的高效是效益上的高效。例如,一個只有幾十到一百訪問量的信息系統,是不是有必要使用EJB技術,這就需要我們綜合的評估效益了。?
安全:安全并不是我們文章討論的重點,卻是架構的一個很重要的方面。

規則?

為了達到上述的目的,我們通常需要對架構設計制定一些簡單的規則:?

功能分解?

顧名思義,就是把功能分解開來。為什么呢?我們之所以很難達到重用目標就是因為我們編寫的程序經常處于一種好像是重復的功能,但又有輕微差別的狀態中。我們很多時候就會經不住誘惑,用拷貝粘貼再做少量修改的方式完成一個功能。這種行為在XP中是堅決不被允許的。XP提倡"Once?and?only?once",目的就是為了杜絕這種拷貝修改的現象。為了做到這一點,我們通常要把功能分解到細粒度。很多的設計思想都提倡小類,為的就是這個目的。

所以,我們的程序中的類和方法的數目就會大大增長,而每個類和方法的平均代碼卻會大大的下降。可是,我們怎么知道這個度應該要如何把握呢,關于這個疑問,并沒有明確的答案,要看個人的功力和具體的要求,但是一般來說,我們可以用一個簡單的動詞短語來命名類或方法的,那就會是比較好的分類方法。?

我們使用功能分解的規則,有助于提高重用性,因為我們每個類和方法的精度都提高了。這是符合大自然的原則的,我們研究自然的主要的一個方向就是將物質分解。我們的思路同樣可以應用在軟件開發上。除了重用性,功能分解還能實現透明的目標,因為我們使用了功能分解的規則之后,每個類都有自己的單獨功能,這樣,我們對一個類的研究就可以集中在這個類本身,而不用牽涉到過多的類。?

根據實際情況決定不同類間的耦合度

雖然我們總是希望類間的耦合度比較低,但是我們必須客觀的評價耦合度。系統之間不可能總是松耦合的,那樣肯定什么也做不了。而我們決定耦合的程度的依據何在呢?簡單的說,就是根據需求的穩定性,來決定耦合的程度。對于穩定性高的需求,不容易發生變化的需求,我們完全可以把各類設計成緊耦合的(我們雖然討論類之間的耦合度,但其實功能塊、模塊、包之間的耦合度也是一樣的),因為這樣可以提高效率,而且我們還可以使用一些更好的技術來提高效率或簡化代碼,例如Java中的內部類技術。可是,如果需求極有可能變化,我們就需要充分的考慮類之間的耦合問題,我們可以想出各種各樣的辦法來降低耦合程度,但是歸納起來,不外乎增加抽象的層次來隔離不同的類,這個抽象層次可以是具體的類,也可以是接口,或是一組的類(例如Beans)。我們可以借用Java中的一句話來概括降低耦合度的思想:"針對接口編程,而不是針對實現編程。

設計不同的耦合度有利于實現透明和延展。對于類的客戶(調用者)來說,他不需要知道過多的細節(實現),他只關心他感興趣的(接口)。這樣,目標類對客戶來說就是一個黑盒子。如果接口是穩定的,那么,實現再怎么擴展,對客戶來說也不會有很大的影響。以前那種牽一發而動全身的問題完全可以緩解甚至避免。?

其實,我們仔細的觀察GOF的23種設計模式,沒有一種模式的思路不是從增加抽象層次入手來解決問題的。同樣,我們去觀察Java源碼的時候,我們也可以發現,Java源碼中存在著大量的抽象層次,初看之下,它們什么都不干,但是它們對系統的設計起著重大的作用。?

夠用就好?:
????我們在上一章中就談過敏捷方法很看重剛好夠用的問題,現在我們結合架構設計來看:在同樣都能夠滿足需要的情況下,一項復雜的設計和一項簡單的設計,哪一個更好。從敏捷的觀點來看,一定是后者。因為目前的需求只有10項,而你的設計能夠滿足100項的需求,只能說這是種浪費。你在設計時完全沒有考慮成本問題,不考慮成本問題,你就是對開發組織的不負責,對客戶的不負責。?

應用模式?

這篇文章的寫作思路很多來源于對模式的研究。因此,文章中到處都可以看到模式思想的影子。模式是一種整理、傳播思想的非常優秀的途徑,我們可以通過模式的方式學習他人的經驗。一個好的模式代表了某個問題研究的成果,因此我們把模式應用在架構設計上,能夠大大增強架構的穩定性。

抽象?

架構的本質在于其抽象性。它包括兩個方面的抽象:業務抽象和技術抽象。架構是現實世界的一個模型,所以我們首先需要對現實世界有一個很深的了解,然后我們還要能夠熟練的應用技術來實現現實世界到模型的映射。因此,我們在對業務或技術理解不夠深入的情況下,就很難設計出好的架構。當然,這時候我們發現一個問題:怎樣才能算是理解足夠深入呢。我認為這沒有一個絕對的準則。?

一次,一位朋友問我:他現在做的系統有很大的變化,原先設計的工作流架構不能滿足現在的要求。他很希望能夠設計出足夠好的工作流架構,以適應不同的變化。但是他發現這樣做無異于重新開發一個lotus?notes。我聽了他的疑問之后覺得有兩點問題:?

首先,他的開發團隊中并沒有工作流領域的專家。他的客戶雖然了解自己的工作流程,但是缺乏足夠的理論知識把工作流提到抽象的地步。顯然,他本身雖然有技術方面的才能,但就工作流業務本身,他也沒有足夠的經驗。所以,設計出象notes那樣的系統的前提條件并不存在。

其次,開發一個工作流系統的目的是什么。原先的工作流系統運作的不好,其原因是有變化發生。因此才有改進工作流系統的動機出現。可是,畢竟notes是為了滿足世界上所有的工作流系統而開發的,他目前的應用肯定達不到這個層次。?

因此,雖然做不到最優的業務抽象,但是我們完全可以在特定目的下,特定范圍內做到最優的業務抽象。比如說,我們工作流可能的變化是工組流路徑的變化。我們就完全可以把工作流的路徑做一個抽象,設計一個可以動態改變路徑的工作流架構。?

有些時候,我們雖然在技術上和業務上都有所欠缺,沒有辦法設計出好的架構。但是我們完全可以借鑒他人的經驗,看看類似的問題別人是如何解決的。這就是我們前面提到的模式。我們不要把模式看成是一個硬性的解決方法,它只是一種解決問題的思路。Martin?Fowler曾說:"模式和業務組件的區別就在于模式會引發你的思考。

在《分析模式》一書中,Martin?Fowler提到了分析和設計的區別。分析并不僅僅只是用用例列出所有的需求,分析還應該深入到表面需求的的背后,以得到關于問題本質的Mental?Model。然后,他引出了概念模型的概念。概念模型就類似于我們在討論的抽象。Martin?Fowler提到了一個有趣的例子,如果要開發一套軟件來模擬桌球游戲,那么,用用例來描述各種的需求,可能會導致大量的運動軌跡的出現。如果你沒有了解表面現象之后隱藏的運動定律的本質,你可能永遠無法開發出這樣一個系統。?

關于架構和抽象的問題,在后面的文章中有一個測量模式的案例可以很形象的說明這個問題。?

架構的一些誤解?

我們花了一些篇幅來介紹架構的一些知識。現在回到我們的另一個主題上來。對于一個敏捷開發過程,架構意味著什么,我們該如何面對架構。這里我們首先要澄清一些誤解:?

誤解1:架構設計需要很強的技術能力。從某種程度來說,這句話并沒有很大的錯誤。畢竟,你的能力越強,設計出優秀架構的幾率也會上升。但是能力和架構設計之間并沒有一個很強的聯系。即使是普通的編程人員,他一樣有能力設計出能實現目標的架構。?

誤解2:架構由專門的設計師來設計,設計出的藍圖交由程序員來實現。我們之所以會認為架構是設計師的工作,是因為我們喜歡把軟件開發和建筑工程做類比。但是,這兩者實際上是有著很大的區別的。關鍵之處在于,建筑設計已經有很長的歷史,已經發展出完善的理論,可以通過某些理論(如力學原理)來驗證設計藍圖。可是,對軟件開發而言,驗證架構設計的正確性,只能夠通過寫代碼來驗證。因此,很多看似完美的架構,往往在實現時會出現問題。?

誤解3:在一開始就要設計出完善的架構。這種方式是最傳統的前期設計方式。這也是為XP所摒棄的一種設計方式。主要的原因是,在一開始設計出完美的架構根本就是在自欺欺人。因為這樣做的基本假設就是需求的不變性。但需求是沒有不變的(關于需求的細節討論,請參看拙作『需求的實踐』)。這樣做的壞處是,我們一開始就限制了整個的軟件的形狀。而到實現時,我們雖然發現原來的設計有失誤之處,但卻不愿意面對現實。這使得軟件畸形的生長。原本一些簡單的問題,卻因為別扭的架構,變得非常的復雜。這種例子我們經常可以看到,例如為兼容前個版本而導致的軟件復雜性。而2000年問題,TCP/IP網絡的安全性問題也從一個側面反映了這個問題的嚴重性。

誤解4:架構藍圖交給程序員之后,架構設計師的任務就完成了。和誤解2一樣,我們借鑒了建筑工程的經驗。我們看到建筑設計師把設計好的藍圖交給施工人員,施工人員就會按照圖紙建造出和圖紙一模一樣的大廈。于是,我們也企圖在軟件開發中使用這種模式。這是非常要命的。軟件開發中缺乏一種通用的語言,能夠充分的消除設計師和程序員的溝通隔閡。有人說,UML不可以嗎?UML的設計理念是好的,可以減輕溝通障礙問題。可是要想完全解決這個問題,UML還做不到。首先,程序員都具有個性化的思維,他會以自己的思維方式去理解設計,因為從設計到實現并不是一項機械的勞動,還是屬于一項知識性的勞動(這和施工人員的工作是不同的)。此外,對于程序員來說,他還極有可能按照自己的想法對設計圖進行一定的修改,這是非常正常的一項舉動。更糟的是,程序員往往都比較自負,他們會潛意識的排斥那些未經過自己認同的設計。

架構設計的過程模式?

通常我們認為模式都是用在軟件開發、架構設計上的。其實,這只是模式的一個方面。模式的定義告訴我們,模式描述了一個特定環境的解決方法,這個特定環境往往重復出現,制定出一個較好的解決方法有利于我們在未來能有效的解決類似的問題。其實,在管理學上,也存在這種類似的這種思維。稱為結構性問題的程序化解決方法。所以呢,我們完全可以把模式的思想用在其它的方面,而目前最佳的運用就是過程模式和組織模式。在我們的文章中,我們僅限于討論過程模式。?方法論對軟件開發而言意味著什么?我們如何看待軟件開發中的方法論?方法論能夠成為軟件開發的救命稻草嗎?在讀過此文后,這些疑惑就會得到解答。?
??架構設計中的方法學(1)——方法源于恐懼

方法論

??方法論的英文為Methodology,詞典中的解釋為:“A series of related methods or techniques”,我們可以把它定義為軟件開發(針對軟件開發)的一整套方法、過程、規則、實踐、技術。關于方法論出現的問題,我很贊同Alistair Cockburn的一句話,“方法論源于恐懼。”出于對項目的超期、成本失控等等因素的恐懼,項目經理們從以前的經驗出發,制定出了一些控制、監測項目的方法、技巧。這就是方法論產生的原因。

??在Agile Software Development一書中,作者提到了方法論的十三個要素,基本能夠函蓋方法論的各個方面:

??角色(Roles)、個性(Personality)、技能(Skills)、團隊(Teams)、技術(Techniques)、活動(Activities)、過程(Process)、工件(Work products)、里程碑(Milestones)、標準(Standards)、質量(Quality)、工具(Tools)、團隊價值(Team Values)。

??它們之間的關系可以用一幅圖來表示:

???
??
圖?1.?方法論的十三個要素

??很多的方法論,都涉及了上面列舉的十三要素中的部分要素,因此,我們可以把方法論看作是一個抽象的、無窮的超集,而現實中的方法論都是指超集的一個有限的子集而已。它們之間的關系就好像有理數和1到100之間的整數的關系一樣。不論是XP,還是UI設計經驗之類,都屬于方法論的一個子集,只是這兩個子集之間有大小的差別而已。我們還應該看到,討論一個完備的方法論是沒有意義的,因此這種方法論鐵定不存在,就好像你視圖窮舉出所有的有理數一樣荒唐。因此,我們關于一個通用的方法論的說法也是無意義的。好的方法論,比如說XP、水晶系列,它們都有一個適合的范圍,因為它們了解一點,自己并不是一個無所不能的方法論。

在現實中,我們其實不斷的在接觸方法論。比如說,為了控制項目的進度,項目經理要求所有的開發人員每周遞交一份詳細的進度報告,這就是一種方法、一種技巧。如果把開發過程中的這些技巧系統的組織起來,就能夠成為一種方法論。你可能會說,那一種方法論的產生也太容易了吧。不,這樣產生的方法論并沒有太大的實用價值,沒有實用價值的方法論根本就沒有存在的必要。因此,一個成功的方法論是要能夠為多個的項目所接受,并且能夠成功實現軟件的交付的方法論。

我和我的同事在實踐中做了一些試驗,希望能夠把一些好的方法論應用于開發團隊。試驗的結果很無奈,方法論實施的效果并不理想,一開始我們認為是方法本身的原因,到后來,我們發現事情并不是這么簡單。在試驗的過程中,開發人員一致認同方法論的優勢所在,但是在實施過程中,鮮有堅持的下來的。在Agile Software Development中,我發現作者遇到了和我們一樣的問題。

Alistair Cockburn在和大量的項目團隊的訪談之后,寫成了Agile Software Development一書。在訪談之前,他篤定自己將會發現高度精確的過程控制是成功的關鍵所在,結果他發現事實并非如此,他把他的發現歸結為7條定律。而我在實際中的發現也包含在這七條定律中,總結起來就只有兩點:溝通和反饋。

只要能夠保證良好的溝通和即時的反饋,那么開發團隊即使并沒有采用先進的方法論,一樣可以成功。相反,那些“高質量”的團隊卻往往由于缺乏這兩個因素而導致失敗(我們這里指的失敗是用戶拒絕使用最終的軟件)。最有效,而成本也最低的溝通方法就是面對面(face to face)的溝通,而隨著項目團隊的變大,或是另外一些影響因素的加入(比如地理位置的隔絕),面對面的溝通越來越難實現,這導致溝通的成本逐漸加大,質量也慢慢下降。但這并不是說非面對面的溝通不可,重要的是我們需要知道不同的溝通方式的成本和質量并不相同。XP方法尤為強調面對面的溝通,通過現場客戶、站立會議、結對編程等方式來保證溝通的有效。在我的經驗中,一個開發團隊其實是需要多種溝通方式的結合的。完全的面對面的溝通對某些團隊來說是很難實現的,那么問題的關鍵就在于你如何應用溝通的方式來達到你希望的效果。在前不久結束的歐萊雅創業計劃大賽上,有一支團隊特別引人注目,他們彼此間素未謀面,僅僅憑借Internet和電話完成了高效的合作。他們雖然沒有使用面對面的溝通方式,但是仍然達成了既定的目標。軟件開發也是一樣的,面對面的溝通是非常有必要的,但其它的溝通方式也是需要的。

再看反饋,不論是控制進度,還是保證客戶的滿意度,這些活動都需要管理成本。軟件開發中的管理成本的一個通性就是伴隨有中間產出物(intermediate delivery)。比如說我們的需求規約、分析文檔、設計文檔、測試計劃,這些都屬于中間產出物。中間產出物的增加將會帶來效率下降的問題,因為開發人員的時間都花在了完成中間產出物的工作上,花在給軟件新功能上的時間就減少了。而中間產出物的主要目的是兩個,一個是為了保證軟件如客戶所愿,例如需求規約;另一個是為了作為團隊中的其他成員工作的輸入,例如開發計劃、測試計劃等。因此,我們也可以針對這兩點來商討對策,一種是采用迭代的思想,提高軟件發布的頻率,以保證客戶的需求被確實的滿足,另一種就是縮小團隊的溝通范圍,保證成員能夠從其他人那里得到新的思路,而不是撰寫規范的內部文檔(內部文檔指那些僅為內部開發人員之間的溝通所需要的文檔)。

因此,一個軟件項目的成功和你采用的開發方法論并沒有直接的關系。

重量

我們根據把擁有大量artifact(RUP官方翻譯為工件,意思是軟件開發過程中的中間產物,如需求規約、設計模型等)和復雜控制的軟件開發方法稱為重型(Heavy Weight)方法,相對的,我們稱artifact較少的方法為輕型(Light Weight)方法。在傳統的觀念中,我們認為重型方法要比輕型安全許多。因為我們之所以想出重型方法,就是由于在中大型的項目中,項目經理往往遠離代碼,他無法有效的了解目前的工程的進度、質量、成本等因素。為了克服未知的恐懼感,項目經理制定了大量的中間管理方法,希望能夠控制整個項目,最典型的莫過于要求開發人員頻繁的遞交各種表示項目目前狀態的報告。

Planning XP一書中有一段討論輕重型方法論的精辟論述,它把重型方法論歸結為一種防御性的姿態(defensive posture),而把輕型方法論歸結為一種渴望成功(Plan to win)的心態。如果你是采用了防御性姿態,那么你的工作就集中在防止和跟蹤錯誤上,大量的工作流程的制定,是為了保證項目不犯錯誤,而不是項目成功。而這種方法也不可謂不好,但前提是如果整個團隊能夠滿足前面所提到的兩個條件的話,項目也肯定會成功,但是重型方法論的一個弊端就在于,大家都在防止錯誤,都在懼怕錯誤,因此人和人之間的關系是很微妙的,要達到充分的溝通也是很難的。最終,連對人的評價也變成是以避免錯誤的多寡作為考評的依據,而不是成就。我們在做試驗的時候,一位項目經理開玩笑說,方法論源自項目經理的恐懼,這沒錯。但最糟糕的是整個團隊只有項目經理一個人恐懼,如果能夠做到人人的恐懼,那大家也就沒有什么好恐懼的了。這句話提醒了我們,如果一個團隊的精神就是力求成功,那么這支團隊的心態就和其它的團隊不同了,尤其是對待錯誤的心態上。根本就沒有必要花費大量的精力來預防錯誤,錯誤犯了就犯了,即時改正就可以了。這其實就是渴望成功的心態。

方法論的藝術

?管理,被稱為科學和藝術的融合體,而管理的藝術性部分很大程度的體現在人的管理上。我說,方法學,一樣是科學和藝術的融合體。這是有依據的,其實方法論和管理學是近親關系,管理學中有一門分支是項目管理,而在軟件組織中,項目管理是非常重要的,方法學就是一種針對軟件開發的一種特定的項目管理(或是項目管理的一個子集)。?

重型方法最大的一個問題就在于他不清楚或忽略了藝術這個層次,忽視了人的因素,把人做為一個計量單位,一種資源,一種線性元素。而人的要素在軟件開發中是非常重要的,軟件開發實際上是一種知識、智力的轉移過程,最終形成的產品是一種知識產品,它的成本取決于開發者的知識價值,因此,人是最重要的因素。而人這個要素是很難衡量的,每個人都有不同的個性、想法、經驗、經歷,這么多復雜的因素加在一起,就導致了人的不可預見性。因此,我們強調管人的藝術。

??最簡單的例子是,在重型方法中,我們的基本假設是對人的不信任。項目經理要控制項目。但不信任就會產生很多的問題,比如士氣不高,計劃趕不上變化,創新能力低下,跳槽率升高等等。人都是希望被尊重的,技術人員更看重這一點,而很多公司也口口聲聲說自己多么多么以人為本,可是采用的卻是以不信任人為前提的開發方法,言行不一。我們說敏捷方法的出發點是相互信任,做到這一點是很難的,但是一旦做到了,那這個團隊就是非常具有競爭力的。因此,這就產生了一個問題,在沒有做到完全的相互信任之前,我們到底相不相信他人呢,這就是我提到的藝術性的問題,什么時候你要相信人?什么時候你不相信人,這些都是需要權衡的問題,也都是表現你藝術性的問題

??敏捷方法

敏捷代表著有效和靈活。我們稱那些輕型的、有效的方法為敏捷方法。在重型方法中,我們在一些不必要、重復的中間環節上浪費了太多的精力,而敏捷則避免了這種浪費。我們的文章將會重點的討論敏捷(Agile)方法論的思想,敏捷這個名字的前身就是輕型。目前已經有了一個敏捷聯盟,他們制定了敏捷宣言:

?Individuals and interactions over processes and tools.

?Working software over comprehensive documentation.

?Customer collaboration over contract negotiation.

Responding to change over following a plan.

而我對敏捷的理解包括了幾個方面

較低的管理成本和高質量的產出。軟件開發存在兩個極端:一個是沒有任何的管理成本,所有的工作都是為了軟件的產出,但是這種方式卻往往導致軟件開發過程的混沌,產品的低質量,團隊士氣的低落。另一個是大量管理活動的加入,評審、變更管理,缺陷跟蹤,雖然管理活動的加入能夠在一定程度上提高開發過程的有序性,但是成本卻因此提高,更糟糕的是,很容易導致團隊的低效率,降低創新能力。因此,敏捷方法試圖尋找一個平衡點,用低成本的管理活動帶來最大的產出,即軟件的高質量。

?尊重人性。敏捷方法尊重人性,強調效率。軟件開發可以說是一種腦力的投入,如果不能保證開發人員的自愿投入,產品就肯定要打折扣。事實多次的證明,一個愿意投入的開發人員和一個不愿意投入的開發人員效率相差在三倍以上,對組織的貢獻更是在十倍以上。

?溝通和反饋是一切的基礎。我們已經討論過溝通的重要程度,而即時的反饋是擁抱變化的前提條件。

?客戶是上帝。沒有客戶就沒有一切,客戶的重要性可以用一句話來形容,就是以合理的成本建造合適的軟件(build the right system at the right cost)。

敏捷其實也有輕重之分,關鍵在于是否能夠做到有效和靈活。因此,敏捷方法論提倡的一個思想是剛好夠(barely sufficient。不過這個剛好夠可不是那么容易判斷的。一支8個人的團隊采用XP方法,隨著方法的熟練使用,團隊的能力在不斷的增強,能夠處理的問題越越來越復雜,也許他們能夠處理采用重型方法的20個人團隊能夠處理的問題。可是如果團隊的人數突然增加到12人,這支團隊肯定就會出問題,他的表現可能還不如那支20個人的團隊了。人數增加的時候,原先的方法肯定還做適當的調整,比如說,在原先的敏捷方法上增加一些重型方法的技巧。我們不能夠要求一支6個人的團隊和一支20個人的團隊用同樣的方法,前者可能采用輕一些的敏捷方法,后者可能采用重一些的敏捷方法,關鍵的問題在于,兩支團隊都把重點放在溝通、反饋、頻繁交付軟件這些關鍵的因素上,也就是做到有效和靈活。

??架構設計

??架構(Architecture)(也有被稱為體系結構的)是軟件設計中非常重要的一個環節。軟件開發的過程中只要需求和架構確定之后,這個軟件就基本上可以定型了。這就好比骨骼確定了,這個人的體形就不會有很大的變化。因此我選擇了架構設計來討論敏捷軟件開發(需求我已經寫過了)。我們在前面討論過超集和子集的概念,因此我們接下去要討論的架構設計也是一個很小的子集。方法論如果沒有經歷過多個項目的檢驗是不能稱為成功的方法論的,我也并不認為我的架構設計就是一個好的方法論,但引玉還需拋磚,他的主要目的是為了傳播一種思想。因此,我采用了模式語言(PLOP)做為寫作架構設計的形式,主要的原因就是模式是一種很好的組織思想的方法

因此,在我們接下去的歷程中,我們集中討論的東西就圍繞著架構、方法學、敏捷這三個要素展開。這篇文章并不是討論如何編碼實現軟件架構的,也不要單純的把它看作架構設計的指南,其實文中的很多思想來自于方法論,因此提到的很多架構設計的思想也適用于其它工作,如果能夠了解這一點,看這篇文章的收獲可能會更多一些。?
架構設計中的方法學(3)——架構源自需求

從需求到架構

??在需求階段,我們可以得到一些代表需求調研成果的中間產物。比如說,CRC卡片、基本用例模型、用戶素材、界面原型、界面原型流程圖

、非功能需求、變化案例等。我們在架構設計階段的主要工作就是要把這些需求階段的中間產物轉換為架構設計階段的中間產物。

??其實,架構設計就是要完成兩項工作,一是分析,二是設計。分析是分析需求,設計則是設計軟件的大致結構。很多的方法論把分析和設計兩種活動分開來,但其實這兩者是很難區分的,做分析的時候會想到如何設計,而思考如何設計反過來又會影響分析的效果。可以說,他們兩者之間是相互聯系和不斷迭代的。這種形態我們將會在后面的迭代設計模式中詳細的討論。

在敏捷方法論中,需求最好是迭代進行的,也就是說一點一點的作需求。這種做法在那些需求變化快的項目中尤其適用。由于我們采用的流程是一種迭代式的流程,這里我們將會面臨著如何對待上一次迭代的中間產物的問題。如果我們每一次迭代都需要修改已存在的中間產物,那么這種維護的成本未免過大。因此,敏捷方法論的基本做法是,扔掉那些已經沒有用處的中間產物。還記得在第一章的時候,我們強調說軟件要比文檔重要。我們生成中間產物的目的都是為了生成最終的程序,對于這些已經完成作用的模型,沒有必要付出額外的維護成本。

不要斷章取義的采用拋棄模型的做法。因為,拋棄模型的做法需要一個適合環境的支持。后面會針對這個話題開展大范圍的討論。這里我們簡單的做一個了解:

?簡單化:簡單的模型和簡單的程序。模型和程序越復雜,就需要更多的精力來處理它們。因此,我們盡可能的簡化它們,為的是更容易的處理它們。

?高效的溝通渠道:通過增強溝通的效果來減少對中間產物的需要。試想一下,如果我隨時能夠從客戶那里得到需求的細節資料,那前期的需求調研就沒有必要做的太細致。

角色的交叉輪換:開發人員之間建立起交換角色的機制,這樣,能夠盡量的避免各子系統諸侯割據的局面。

清晰的流程:或者我們可以稱之為明確的過程。過程在方法論中向來都是一個重點,敏捷方法論也不例外。開發人員能夠清楚的知道,今天做什么,明天做什么。過程不是給別人看的,而是給自己用的。

工具:好用的工具能夠節省大量的時間,這里的工具并不僅僅指CASE工具,還包括了版本控制工具、自動化測試工具、畫圖工具、文檔制作和管理工具。使用工具要注意成本和效益的問題。

標準和風格:語言不通是溝通的一個很大的障礙。語言從某個角度來看屬于一種標準、一種風格。因此,一個團隊如果采用同樣的編碼標準、文檔標準、注釋風格、制圖風格,那么這個團隊的溝通效率一定非常的高。

如果上述的環境你都不具備,或是欠缺好幾項,那你的文檔的模型還是留著的好。

?僅針對需求設計架構

僅針對需求設計架構的含義就是說不要做未來才有用的事情。有時候,我們會把架構考慮的非常復雜,主要的原因就是我們把很多未來的因素放入到現在來考慮。或者,我們在開發第一個產品的時候就視圖把它做成一個完美的框架。以上的這兩種思路有沒有錯呢?沒有錯,這只是如何看待投入的問題,有人希望開始的時候多投入一些,這樣后續的投入就會節省下來。但在現實中,由于需求的不確定性,希望通過增加開始階段的投入來將降低未來的投入往往是難以做到的,框架的設計也絕對不是能夠一蹴而就的,此這種做法并不是一個好的做法。所以我們在后頭會著重論述架構設計的簡單性和迭代過程,也就是因為這個理由。

??模式??

模式將可以幫助我們抓住重點。為了解決設計文檔編輯器引出的七個問題,一共使用了8種不同的模式。這8種模式的組合其實就是架構,因為它們解決的,都是系統中最高層的問題。?
???
??在實踐中,人們發現架構也是存在模式的。比如,對于系統結構設計,我們使用層模式;對于分布式系統,我們使用代理模式;對于交互系統,我們使用MVC(模型-視圖-控制器)模式。模式本來就是針對特定問題的解,因此,針對需求的特點,我們也可以采用相應的模式來設計架構。
?
???
??在sun網站上提供的寵物商店的范例中,就把MVC模式的思想擴展成為架構的思想,用于提供不同的界面視圖:
?
???
?
???
??
我們可以了解到在圖的背后隱藏著的需求:系統需要支持多種用戶界面,包括為普通用戶提供的HTML界面,為無線用戶提供的WML界面,為管理員提供的Swing界面,以及為B2B業務設計的WebService界面。這是系統最重要的需求,因此,系統的設計者就需要確定一個穩定的架構,以解決多界面的問題。相對于多界面的問題,后端的業務處理邏輯都是一致的。比如HTML界面和WML界面的功能并沒有太大的差別。把處理邏輯和界面分離開來還有額外的好處,可以在添加功能的同時,不涉及界面的改動,反之亦然。這就是我們在第二篇中提到的耦合度的問題。????
??MVC模式正可以適用于解決該問題。系統使用控制器來為業務邏輯選擇不同的界面,這就完成了MVC架構的設計思路。在架構設計的工作中,我們手頭上有模式這樣一張好牌,有什么理由不去使用它呢?
?
???抓住重點
???
??在架構設計一開始,我們就說架構是一種抽象,那就是說,架構設計摒棄了具體的細節,僅僅抓住軟件最高層的概念,也就是最上層、優先級最高、風險最大的那部分需求。
????
??我們考慮、分析、解決一個問題,一定有一個漸進的過程。架構設計就是解決問題其中比較早期的一個階段,我們不會在架構設計這個階段投入過多的時間(具體的原因在下文會有討論),因此關鍵點在于我們要能夠在架構設計中把握住需求的重點。比如,我們在模式一節中提到了分布式系統和交互系統,分布和交互就是這兩個系統的重點。那么,如果說我們面對的是一個分布式的交互系統,那么,我們就需要把這兩種特性做為重點來考慮,并以此為基礎,設計架構。而我們提到的寵物商店的范例也是類似的,除了MVC的架構,還有很多的設計問題需要解決,例如用于數據庫訪問的數據對象,用于視圖管理的前端控制器,等等(具體使用到的架構模式可以訪問sun的網站)。但是這些相對于MVC模式來說,屬于局部的,優先級較低的部分,可以在架構確定后再來設計。
????
??架構設計和領域專家
????
??一個架構要設計的好,和對需求的理解是分不開的。因此在現實中,我們發現業務領域專家憑借著他對業務領域的了解,能夠幫助開發人員設計出優秀的架構來。架構是需要抽象的,它是現實社會活動的一個基本模型,而業務領域的模型僅僅憑開發人員是很難設計出來的。在ERP的發展史上,我們看到MRP發展為MRPII,在發展到閉環MRP,直到發展成為現在的ERP,主要的因素是管理思想的演化,也就是說,對業務領域的理解進步了,架構才有可能進步。
????
??因此,敏捷型架構設計的過程中,我們也非常強調領域專家的作用

架構設計中的方法學(4)——團隊設計

團隊設計是敏捷方法論中很重要的一項實踐。我們這里說的團隊,指的并不是復數的人。一群人就是一群人,并沒有辦法構成團隊。要想成為團隊,有很多的工作要做。
??我們之所以考慮以團隊

為單位來考慮架構設計,是因為軟件開發本身就不是一件個人的事情,架構設計更是如此。單個人的思維不免有考慮欠妥之處,單個人的學識也不可能覆蓋所有的學科。而組織有效的團隊卻能夠彌補這些缺憾。????
??誰來負責架構的設計?
????
??在我們的印象中,總認為架構設計是那些所謂架構設計師的專屬工作,他們往往擁有豐富的設計經驗和相關的技能,他們不用編寫代碼,就能夠設計出理論上盡善盡美的架構,配有精美的圖例。
?
???問題1:理論上設計近乎完美的架構缺乏程序的證明,在實際應用中往往會出這樣那樣的問題。
?
???問題2:設計師設計架構帶有很大的主觀性,往往會忽視客戶的需求,導致架構無法滿足需求。
?
???問題3:實現的程序員對這種架構有抵觸的情緒,或是因為不理解架構而導致架構實現的失敗。
?
???問題4:架構師設計架構主要是依據自己的大量經驗,設計出的架構不能真實的反映目前的軟件需要。
?
???解決辦法
?
?? ?團隊設計的理論依據是群體決策。和個人決策相比,群體決策的最大好處就是其結論要更加的完整。而群體決策雖然有其優點,但其缺點也是很明顯的:需要額外付出溝通成本、決策效率低、責任不明確、等等。但是群體決策如果能夠組織得當的話,是能夠在架構設計中發揮很大的優勢的

??避免象牙塔式的架構設計

??對軟件來說,架構設計是一項至關重要的工作。這樣的工作交給某個人是非常危險的。即便這個人再怎么聰明,他也可能會遺漏部分的細節。組織有效的團隊的力量是大大超過個人的力量的,因此團隊的成果較之個人的成果,在穩定性和思考的周密程度上,都要更勝一籌。

??Scott W. Ambler在其著作中給出了象牙塔式架構(ivory tower architecture)的概念:???
??An ivory tower architecture is one that is often developed by an architect or architectural team in relative isolation to the day-to-day development activities of your project team(s). ???
??中國現在的軟件開發行業中也逐漸出現了象牙塔式的架構設計師。這些架構師并不參與實際的程序編寫,他的工作就是為項目制作出精美的架構模型,這種架構模型在理論上是相當完美的。
????
??例1:在XP中,我們基本上看不到架構設計的影子。并不是說采用XP技術的團隊就不需要架構設計。XP不存在專門的設計時期,它提倡使用一些簡單的圖例、比喻的方式來表達軟件的架構,而這種的架構設計是無時無刻不在進行的。其實,XP中的設計采用的就是團隊設計的方式,結隊編程(Pair Programming)和代碼的集體所有制(Collective Ownership)是團隊設計的基礎,也就是基于口述的溝通方式。通過采用這樣的方式,XP幾乎不需要文檔來表達架構的設計。

??優秀的架構師能夠充分的利用現有框架,減少軟件的投入,增強軟件的穩定性。這些都沒有錯,但是問題在于“過猶不及”。象牙塔式架構師往往會出現文章開始指出的那些問題。架構設計其實并不是非常復雜的工作,但它要求開發人員具備相關的技能、經驗以及對問題域有一定的了解。開發人員往往都具有相關的技術技能(編程、數據庫設計、建模),而對問題域的理解可以從用戶和行業專家那里獲得幫助。因此,在理論上,我們要實現架構設計的團隊化是完全可能的。???
??在上面的象牙塔式架構定義中,我們看到架構師和日常的開發工作是隔絕的。這樣設計出的架構有很大的局限性。在現實中,我們還會發現另外一種角色,他來自于開發團隊外部,為開發人員提供相關的技術或業務的培訓。這種角色稱為教練,在軟件開發中是非常重要的角色,不能夠和象牙塔式架構設計師之間畫等號。

??選擇你的設計團隊

??軟件的架構在軟件的生命周期的全過程中都很重要,也就是說,軟件開發團隊中的所有人員都需要和架構打交道。因此,最好的團隊組織方式是所有開發人員都參與架構的設計,我們稱這種方式為全員參與。全員參與的方式保證了所有開發人員都能夠對架構設計提出自己的見解,綜合多方面的意見,在全體開發人員中達成一致。這種方式尤其適合于一些小的團隊。

??還是會有很多的團隊由于種種的原因不適合采用全員參與的方式。那么,組織優秀的開發人員組成設計組也是比較好的方式。一般,我們選擇那些在項目中比較重要的,有較多開發經驗,或是理論扎實的那些人來組成設計組。當然,如果你考慮到為組織培養后續力量,你也可以讓一些新手加入設計組,或是你覺得自己的開發力量不足,邀請外部的咨詢力量介入,這完全取決于具體的情況。

??設計組不同于我們之前提到的象牙塔式架構設計師。設計組設計出來的架構只能稱為原始架構,它是需要不斷的反饋和改進的。因此,在架構實現中,設計組的成員將會分布到開發團隊的各個領域,把架構的思想帶給所有開發人員,編寫代碼來檢驗架構,并獲得具體的反饋,然后所有的成員再集中到設計組中討論架構的演進。

??團隊設計中存在的問題

在團隊設計的過程,我們會遇到各種各樣的問題,首當其沖的就是溝通成本的問題。架構設計時,需求尚未被充分理解,軟件的設計思路還處于萌發的狀態。這樣的情況下,團隊的每位成員對軟件都有獨特的見解,這些可能有些是相同的,有些是互斥的。就好比盲人摸象一樣,他們的觀點都代表了軟件的一部分或是一方面,但是沒有辦法代表軟件的全部。

??在敏捷方法論中,我們的每一個流程都是迅速進行、不斷改進的。架構設計也是一樣,我們不可能在一次架構設計上花費更多的時間。而團隊決策總是傾向于較長的討論和權衡。

2中的問題在架構設計中時有發生,純技術的討論很容易上升稱為爭吵。這種情況幾乎沒有辦法完全避免。團隊型的決策必然會發生觀念的沖突。控制一定程度內的觀念的沖突對團隊的決策是有益,但是如果超出了這個程度就意味著失控了,需要團隊領導者的調節。而更重要的,我們需要注意溝通的技巧

團隊溝通

?團隊進行架構設計的時候溝通是一個非常需要注意的問題,上述的情境在軟件組織中是經常發生的,因為技術人員很自然認為自己的技術比別人的好,如果自己的技術受到質疑,那怕對方是抱著討論的態度,也無異于自身的權威受到了挑戰,面子是無論如何都需要捍衛的。而溝通如果帶上了這樣一層主觀色彩,那么溝通信息的受眾就會潛意識的拒絕接受信息。相反,他會找出對方話語中的漏洞,準備進行反擊。因此,我們要注意培養一種良好的溝通氛圍。

在實際的觀察中,我發現團隊溝通中存在兩種角色,一種是建議者,他們經常能夠提���建議。一種是質疑者,他們對建議提出否定性的看法。這兩種角色是可能互換的,現在的建議者可能就是剛才的質疑者。質疑者的發言是很能打擊建議者的積極性的,而在一個腦力激蕩的會議中,最好是大家都能夠扮演建議者的角色,這就要求溝通會議的主持者能夠掌握好這一點,對建議給予肯定的評價,并鼓勵大家提出新的建議。

??例2:敏捷方法非常注重的就是團隊的溝通。溝通是一個很有意思的話題,講起來會花費大量的時間,我們這里只是針對架構設計中可能存在的溝通問題做一個簡單的討論。我們這里假設一個討論情境,這個情境來源于真實的生活:項目主管徐輝、設計師李浩、設計師羅亦明正在討論一個新的軟件架構。?"李浩你認為這個軟件數據庫連接部分應該如何考慮?"徐輝問。李浩想了想,"我覺得方案A不錯…" "方案A肯定有問題!這個軟件和上一次的又不同。"羅亦明打斷了李浩的發言。?"你懂什么!你到公司才多久,方案A是經過很長時間的證明的!"發言被打斷,李浩有點惱火,羅亦明進入公司沒有多久,但在一些事情上老是和他唱反調。?"我進公司多久和方案A的錯誤有什么關系!"?在這樣一種氛圍中,會議的結果可想而知。良好的溝通有助于架構設計工作的開展。一個成員的能力平平的團隊,可以藉由良好的溝通,設計出優秀的架構,而一個擁有一個優秀成員的團隊,如果缺乏溝通,最后可能連設計都出不來。這種例子現實中可以找到很多。

?標準和風格

我們總是在不知不覺之中使用各種各樣的標準和風格。在團隊設計中,我們為了提高決策的效率,可以考慮使用統一的標準和風格。統一的標準和風格并不是一朝一夕形成的。因為每個人都有自己不同的習慣和經歷,強制性的要求開發人員使用統一的標準(風格)容易引起開發人員的不滿。因此在操作上需要注意技巧。對架構設計而言,比較重要的標準(風格)包括界面設計、流程設計、建模規范、編碼規范、持久層設計、測試數據。

在我的經驗中,有一些組織平時并不注意標準(風格)的積累,認為這種積累屬于雕蟲小技,但正是這些小技,能夠非常有效的提高溝通的效率和降低開發人員的學習曲線。試想一下,如果一個團隊中所有人寫出的代碼都是不同標準和風格的,那么理解起來肯定會困難許多。當然,我們沒有必要自己開發一套標準(風格)出來,現實中有很多可以直接借用的資料。最好的標準是UML語言,我們可以從UML的官方網站下載到最新的規范,常用的編碼標準更是隨處可見。不過雖然有了統一的標準,如果風格不統一,同樣會造成溝通的障礙。例如下圖顯示的類圖,雖然它們表示的是同一個類,但是由于版型、可視性、詳細程度的差別,看起來又很大的差別。而在其它的標準中,這種差別也是普遍存在的。因此,我們在使用了統一的標準之后,還應該使用同樣的風格。Scott W. Ambler專門成立了一個網站討論UML的建模風格的相關問題,有興趣的讀者可以做額外的閱讀。????
??
???
??
圖?4.?兩種風格的類圖

??在統一的風格的基礎上更進一步的是使用術語。使用溝通雙方都了解專門的術語,可以代表大量的信息。最好的術語的范例就是設計模式的模式名。如果溝通的雙方都了解設計模式,那么一方只需要說這部分的設計可以使用工廠模式,另一方就能夠理解,而不用再詳細的解釋設計的思路。這種的溝通方式是最高效的,但它所需要的學習曲線也會比較陡。

團隊設計的四明確

為了最大程度的提高團隊設計的高效性,可以從4個方面來考慮:???
??1、明確目標

?泛泛的召開架構討論會議是沒有什么意義的,一個沒有鮮明主題的會議也不會有什么結果。在源自需求的模式中,我們談到說可以有非功能需求的架構,可以有功能需求的架構。因此,在進行團隊設計之前,我們首先也需要確定,此次要解決什么問題,是討論業務邏輯的架構,還是技術架構;是全局性的架構,還是各模塊的架構。

??2、明確分工

我們之所以重視團隊,很重要的額一個原因就是不同的成員有不同的擅長的區域。有些成員可能擅長于業務邏輯的建模,有的擅長于原型設計,有的擅長于數據庫設計,有的則擅長于Web編程。你能夠想象一個軟件沒有界面嗎?(有些軟件可能是這種情況)你能夠想象一個軟件只有數據庫,而沒有處理邏輯嗎?因此,架構設計就需要綜合的考慮各個方面,充分利用成員的優勢。這就要求團隊的各個成員都能夠明確自己的分工。

??3、明確責權

??除了明確自己的分工,每位成員都需要清楚自己的責任。沒有責任,分工就不會有任何的效力。每位成員都需要明確自己要做些什么。當然,和責任相對的,沒有成員還需要知道自己的權力是什么。這些清楚了,進行高效的溝通的前提就具備了。每次架構的討論下來,每個人都清楚,自己要做些什么,自己需要要求其他人做些什么,自己該對誰負責。如果這些問題回答不了,那這次的討論就白費了。

??4、明確溝通方式

??這里使用溝通方式可能有一點點不恰當,為了明確的表達意思,大家可以考慮信息流這個詞。一個完整架構包括幾個方面,分別都由那些人負責,如何產生,產生的整個過程應該是什么樣的?這樣的一個信息流程,囊括了上面提到的三個明確。如果團隊的每一個人都能夠為架構的產生而努力,并順利的設計出架構,那么這樣的流程是完美的。如果你發現其中的一些人不知道做些什么,那么,這就是流程出問題的現象了。完美的流程還會有一個額外的副產品,架構產生之后,團隊對于軟件的設計已經是非常的清晰了。因為我們提倡的是盡可能多的開發人員參與架構的設計。

不僅僅是架構?討論到這里,其實有很多的內容已經脫離了架構設計了。也就是說,很多的原則和技巧都是可以用于軟件開發的其它活動的。至于哪一些活動能夠利用這些方法呢?大家可以結合自己的實際情況,來思考這個問題。提示一點,關鍵的入手處在于目前效率較低之處。

架構設計中的方法學(5)——簡單設計

XP非常強調簡單的設計原則:能夠用數組實現的功能決不用鏈表。在其它Agile方法中,簡單的原則也被反復的強調。在這篇文章,我們就對簡單性做一個全面的了解。???
??架構應該設計到 什么程度?

????軟件的架構都是非常的復雜的,帶有大量的文檔和圖表。開發人員花在理解架構本身上的時間甚至超出了實現架構的時間。在前面的文章中,我們提到了一些反對象牙塔式架構的一個原因,而其中的一個原因就是象牙塔式架構的設計者往往在設計時參雜進過多的自身經驗,而不是嚴格的按照需求來進行設計。

在軟件開發領域,最為常見的設計就是"Code and Fix"方式的設計,設計隨著軟件開���過程而增長。或者,我們可以認為這種方式根本就不能算是設計,它抱著一種船到橋頭自然直的態度,可是在設計不斷改動之后,代碼變得臃腫且難以理解,到處充滿著重復的代碼。這樣的情形下,架構的設計也就無從談起,軟件就像是在風雨中的破屋,瀕臨倒塌。

針對于這種情形,新的設計方式又出現了,Martin Fowler稱這種方式為"Planned Design"。和建筑的設計類似,它強調在編碼之前進行嚴格的設計。這也就是我們在團隊設計中談到的架構設計師的典型做法。設計師們通常不會去編程,理由是在土木工程中,你不可能看到一位設計師還要砌磚頭。

?"Planned Design"較之"Code and Fix"進步了許多,但是還是會存在很多問題。除了在團隊設計中我們談的問題之外,需求變更將會導致更大的麻煩。因此,我們理所當然的想到進行"彈性設計":彈性的設計能夠滿足需求的變更。而彈性的設計所付出的代價就是復雜的設計

題外話:

這里我們談論"Planned Design"引出的一些問題,并沒有任何排斥這種方式的意思。"Planned Design"還是有很多可取之處的,但也有很多需要改進的地方。事實上,本文中我們討論的架構設計方式,本質上也是屬于"Planned Design"方式。和"Planned Design"相對應的方式是XP所主張的"Evolutionary Design"方式,但是這種方式還有待于實踐的檢驗,并不能簡單的說他就一定要比"Planned Design"先進或落后。但可以肯定的一點是:"Evolutionary Design"方式中有很多的思想和技巧是值得"Planned Design"借鑒的。

解決方法:

XP中有兩個非常響亮的口號:"Do The Simplest Thing that Could Possibly Work"和"You Aren't Going to Need It"(通常稱之為YAGNI)。他們的核心思想就是不要為了考慮將來,把目前并不需要的功能加到軟件中來。

粗看之下,會有很多開發人員認為這是不切實際的口號。我能理解這種想法,其實,在我熱衷于模式、可重用組件技術的時候,我對XP提倡的簡單的口號嗤之以鼻。但在實際中,我的一些軟件因為復雜設計導致開發成本上升的時候,我重新思考這個問題,發現簡單的設計是有道理的。

?降低開發的成本

不論是模式,可重用組件,或是框架技術,目的都是為了降低開發的成本。但是他們的方式是先進行大量的投入,然后再節省后續的開發成本。因此,架構設計方面的很多思路都是圍繞著這種想法展開的,這可能也是導致開發人員普遍認為架構設計高不可攀的原因。XP的方式恰恰相反,在處理第一個問題的時候,不必要也不可能就設計出具有彈性、近乎完美的架構來。這項工作應該是隨著開發的演進,慢慢成熟起來的。我不敢說這種方式肯定正確,但是如果我們把生物的結構視同為架構,這種方式不是很類似于自然界中生物的進化方式嗎?

在一開始就制作出完美的架構的設想并沒有錯,關鍵是很難做到這一點。總是會有很多的問題是你在做設計時沒有考慮到的。這樣,當一開始花費大量精力設計出的"完美無缺"的架構必然會遇到意想不到的問題,這時候,復雜的架構反而會影響到設計的改進,導致開發成本的上升。這就好比如果方向錯了,交通工具再快,反而導致錯誤的快速擴大。Martin Fowler在他的論文中說,"Working on the wrong solution early is even more wasteful than working on the right solution early"(提前做一件錯事要比提前做一件對的事更浪費時間),相信也是這個道理。

更有意思的是,通常我們更有可能做錯。在我們進行架構設計的時候,我們不可能完全取得詳細的需求。事實上,就算你已經取得了完整的需求,也有可能發生變化。這種情況下做出的架構設計是不可能不出錯的。這樣,浪費大量的時間在初始階段設計不可能達到的"完美架構",倒不如把時間花在后續的改進上。

提升溝通的效率?

我們在團隊設計中已經談過了團隊設計的目標之一就是為了降低溝通的成本,以期讓所有人都能夠理解架構。但是如果架構如果過于復雜,將會重新導致溝通成本的上升,而且,這個成本并不會隨著項目進行而降低,反而會因為上面我們提到的遇到新的問題導致溝通成本的持續上升。

簡單的架構設計可以加快開發團隊理解架構的速度。我們可以通過兩種方式來理解簡單的含義。首先,簡單意味著問題的解不會非常的復雜,架構是解決需求的關鍵,無論需求再怎么復雜多變,總是可以找出簡單穩定的部分,我們可以把這個簡單穩定的部分做為基礎,再根據需要進行改進擴展,以解決復雜的問題。在示例中,我們提到了measurement pattern,它就是按照這種想法來進行設計的。

其次,簡單性還體現在表示的簡單上。一份5頁的文檔就能夠表達清楚的架構設計為什么要花費50頁呢?同樣的道理,能夠用一副簡單的圖形就能夠表示的架構設計也沒有必要使用文檔。畢竟,面對面的溝通才是最有效率的溝通,文檔不論如何的復雜,都不能被完全理解,而且,復雜的文檔,維護起來也需要花費大量的時間。只有在兩種情況下,我們提倡使用復雜的文檔:一是開發團隊沒有辦法做到面對面溝通;二是開發成果要作為團隊的知識積累起來,為下一次開發所用。

考慮未來

??我們之所以考慮未來,主要的原因就是需求的不穩定。因此,我們如果考慮未來可能發生的需求變化,就會不知覺的在架構設計中增加復雜的成分。這違背的簡單的精神。但是,如果你

不考慮可能出現的情況,那些和目前設計格格不入的改變,將會導致大量的返工。

還記得YAGNI嗎?原則上,我們仍然堅持不要在現有的系統中為將來可能的情況進行設計。但是,我們必須思考,必須要為將來可能出現的情況做一些準備。其實,軟件中了不起的接口的思想,不就是源于此嗎?因此,思考未來,但等到需要時再實現。

變更案例有助于我們思考未來,變更案例就是你在將來可能要(或可能不要)滿足的,但現在不需要滿足的需求。當我們在做架構設計的時候,變更案例也將會成為設計的考慮因素之一,但它不可能成為進行決策的唯一考慮因素。很多的時候,我們沉迷于設計通用系統給我們帶來的挑戰之中,其實,我們所做的工作對用戶而言是毫無意義的。

架構的穩定?
???架構簡單化和架構的穩定性有什么關系嗎?我們說,架構越簡單,其穩定性就越好。理由很簡單,1個擁有4個方法和3個屬性的類,和1個擁有20個方法和30屬性的類相比,哪一個更穩定?當然是前者。而架構最終都是要映射到代碼級別上的,因此架構的簡單將會帶來架構的穩定。盡可能的讓你的類小一些,盡可能的讓你的方法短一些,盡可能的讓類之間的關系少一些。這并不是我的忠告,很多的設計類的文章都是這么說的。在這個話題上,我們可以進一步的閱讀同類的文章(關于?refactoring?的思考)。

辨正的簡單

因此,對我們來說,簡單的意義就是不要把未來的、或不需要實現的功能加入到目前的軟件中,相應的架構設計也不需要考慮這些額外的需求,只要剛好能夠滿足當前的需求就好了。這就是簡單的定義。可是在現實之中,總是有這樣或者那樣的原因,使得設計趨向復雜。一般來說,如果一個設計對團隊而言是有價值的,那么,付出一定的成本來研究、驗證、發展、文檔化這個設計是有意義的。反之,如果一個設計沒有很大的價值或是發展它的成本超過了其能夠提供的價值,那就不需要去考慮這個設計。

價值對不同的團隊來說具有不同的含義。有時候可能是時間,有時候可能是用戶價值,有時候可能是為了團隊的設計積累和代碼重用,有時候是為了獲得經驗,有時候是為了研究出可重用的框架(FrameWork)。這些也可以稱為目的,因此,你在設計架構時,請注意先確定好你的目的,對實現目的有幫助的事情才考慮。

Scott W.Ambler在他的文章中提到一個他親身經歷的故事,在軟件開發的架構設計過程中,花了很多的時間來設計數據庫到業務邏輯的映射架構,雖然這是一件任何開發人員都樂意專研的事情(因為它很酷)。但他不得不承認,對用戶來說,這種設計先進的架構是沒有太大的意義的,因為用戶并不關心具體的技術。當看到這個故事的時候,我的觸動很大。一個開發人員總是熱衷于新奇的技術,但是如果這個新奇技術的成本由用戶來承擔,是不是合理呢?雖然新技術的采用能夠為用戶帶來效益,但是沒有人計算過效益背后的成本。就我開發過的項目而言,這個成本往往是大于效益的。這個問題可能并沒有確定的答案,只能是見仁見智了。

簡單并不等于實現簡單

說到這里,如果大家有一個誤解,認為一個簡單的架構也一定是容易設計的,那就錯了。簡單的架構并不等于實現起來也簡單。簡單的架構需要設計者花費大量的心血,也要求設計者對技術有很深的造詣。在我們正在進行的一個項目中,一開始設計的基礎架構在實現中被修改了幾次,但每修改一次,代碼量都減少一分,代碼的可讀性也就增強一分。從心理的角度上來說,對自己的架構進行不斷的修改,確實是需要一定的勇氣的。因為不論是設計還是代碼,都是開發人員的心血。但跨出這一步是值得的。

下面的例子討論了Java的IO設計,Java類庫的設計應該來說是非常優秀的,但是仍然避免不了重新的修改。實際上,在軟件開發領域,由于原先的設計失誤而導致后來設計過于復雜的情況比比皆是(例如微軟的OLE)。同樣的,我們在設計軟件的時候,也需要對設計進行不斷的修改。能夠實現復雜功能,同時自身又簡單的設計并不是一件容易的事情。

例1.???????????Java的IO系統?
??從Java的IO系統設計中,我們可以感受到簡單設計的困難。

例2.????????IO系統設計的困難性向來是公認的。Java的IO設計的一個目的就是使IO的使用簡單化。在Java的1.0中,Java的IO系統主要是把IO系統分為輸入輸出兩個大部分,并分別定義了抽象類InputStream和OutputStream。從這兩個的抽象類出發,實現了一系列不同功能的輸入輸出類,同時,Java的IO系統還在輸入輸出中實現了FilterInputStream和FilterOutputStream的抽象類以及相關的一系列實現,從而把不同的功能的輸入輸出函數連接在一起,實現復雜的功能。這個實現其實是Decorator模式(由于沒有看過源碼和相關的資料,這里僅僅是根據功能和使用技巧推測,如果大家有不同的意見,歡迎來信討論)。?
??因此,我們可以把多個對象疊加在一起,提供復雜的功能:
?
??DataInpuStream in =?
??new DataInputStream(?
??new BufferedInputStream(?
??new FileInputStream("test.txt");?
???
??上面的代碼使用了兩個FilterInputStream:DataInpuStream和BufferedInputStream,以實現讀數據和緩沖的功能,同時使用了一個InputStream:FileInputStream,從文件中讀取流數據。雖然使用起來不是很方便,但是應該還是非常清晰的設計。
?
??令設計混亂的是既不屬于InputStream,也不屬于OutputStream的類,例如RandomAccessFile,這正表明,由于功能的復雜化,使得原先基于輸入輸出分類的設計變得混亂,根據我們的經驗,我們說設計需要Refactoring了。因此,在Java1.1中,IO系統被重新設計,采用了Reader和Writer位基礎的設計,并增加了新的特性。但是目前的設計似乎更加混亂了,因為我們需要同時使用1.0和1.1兩種不同的IO設計

?架構設計中的方法學(6)——迭代設計

  迭代是一種軟件開發的生命周期模型,在設計中應用迭代設計,我們可以得到很多的好處。

  在軟件生命周期中,我們如何對待架構設計的發展?

  架構設計往往發生在細節需求尚未完成的時候進行的。因此,隨著項目的進行,需求還可能細化,可能變更。原先的架構肯定會有不足或錯誤的地方。那么,我們應該如何對待原先的設計呢?

  我們在簡單設計模式中簡單提到了"Planned Design"和"Evolutionary Design"的區別。XP社團的人們推崇使用"Evolutionary Design"的方式,在外人看來,似乎擁護者們從來不需要架構的設計,他們采用的方式是一開始就進入代碼的編寫,然后用Refactoring來改進代碼的質量,解決未經設計導致的代碼質量低下的功能。

  從一定程度上來說,這個觀點并沒有錯,它強調了代碼對軟件的重要性,并通過一些技巧(如Refactoring)來解決缺乏設計的問題。但我并不認同"Evolutionary Design"的方式,在我看來,一定程度上的"Planned Design"是必須的,至少在中國的軟件行業中,"Planned Design"還沒有成為主要的設計方向。借用一句明言,"凡事預則立,不預則廢",在軟件設計初期,投入精力進行架構的設計是很有必要的,這個架構是你在后續的設計、編碼過程中依賴的基礎。但是,一開始我們提到的設計改進的問題依然存在,我們如何解決它呢?

  在簡單設計模式中,我們提到了設計改進的必要性,但是,如果沒有一種方法去控制設計的改進的話,那么設計改進本身就是一場噩夢。因此,何時改進,怎么改進,如何控制,這都是我們需要面對的問題。

  解決方法

  為了實現不斷的改進,我們將在開發流程中引入迭代的概念。迭代的概念在《需求的實踐》中已經提到,這里我們假設讀者已經有了基本的迭代的概念。

  軟件編碼之前的工作大致可以分為這樣一個工作流程:

  上圖中的流程隱含著一個信息的損失的過程。來自于用戶的需求經過整理之后,開發人員就會從中去掉一些信息,同樣的事情發生在后面的過程中,信息丟失或變形的情況不斷的發生。這里發生了什么問題?應該說,需求信息的失真是非常普遍的,我們缺少的是一種有效的辦法來抑止失真,換句話說,就是缺少反饋。

  如果把眼睛蒙上,那我們肯定沒有辦法走出一條很長的直線。我們走路的時候都是針對目標不斷的調整自己的方向的。同樣的,漫長的軟件開發過程如果沒有一種反饋機制來調整方向,那最后的軟件真是難以想象。

  所以我們引入了迭代周期。
  初始設計和迭代設計?
  在團隊設計中,我們一直在強調,設計組最開始得到的設計一定只是一個原始架構,然后把這個原始架構傳播到每一位開發者的手中,從而在開發團隊中形成共同的愿景。(愿景(Vision):源自于管理學,表示未來的愿望和景象。這里借用來表示軟件在開發人員心中的樣子。在后面的文章中我們會有一個章節專門的討論架構愿景。)

  迭代(Iterate)設計,或者我們稱之為增量(Incremental)設計的思想和XP提倡的Evolutionary Design有異曲同工之妙。我們可以從XP、Crystal、RUP、ClearRoom等方法學中對比、體會迭代設計的精妙之處:每一次的迭代都是在上一次迭代的基礎上進行的,迭代將致力于重用、修改、增強目前的架構,以使架構越來越強壯。在軟件生命周期的最后,我們除了得到軟件,還得到了一個非常穩定的架構。對于一個軟件組織來說,這個架構很有可能就是下一個軟件的投入或參考。

  我們可以把早期的原始架構當作第一次迭代前的早期投入,也可以把它做為第一次迭代的重點,這些都是無所謂的。關鍵在于,原始架構對于后續的架構設計而言是非常重要的,我們討論過架構是來源于需求的,但是原始架構應該來源于那些比較穩定的需求。

  TIP:現實中迭代設計退化為"Code and Fix"的設計的情況屢見不鮮("Code and Fix"參見簡單設計)。從表面上看,兩者的做法并沒有太大的差別,都是針對原有的設計進行改進。但是,二者效果的差別是明顯的:"Code and Fix"是混沌的,毫無方向感可言,每一次的改進只是給原先就已搖搖欲墜的積木上再加一塊積木而已。而迭代設計的每一次改進都朝著一個穩定的目標在前進,他給開發人員帶來信心,而不是打擊。在過程上,我們說迭代設計是在控制之下的。從實踐的經驗中,我們發現,把原該在目前就該解決的問題退后是造成這一問題的主要原因之一。因此,請嚴格的對待每一次的迭代,確保計劃已經完成、確保軟件的質量、確保用戶的需求得到滿足,這樣才是正統的迭代之路。

  單次的迭代?
  我們說,每一次的迭代其實是一個完整的小過程。也就是說,它同樣要經歷文章中討論的這些過程模式。只不過,這些模式的工作量都不大,你甚至可以在很短的時間內做完所有的事情。因此,我們好像又回到了文章的開頭,重新討論架構設計的過程。

  單次迭代最令我們興奮的就是我們總是可以得到一個在當前迭代中相當穩定的結果,而不像普通的架構設計那樣,我們深怕架構會出現問題,但又不得不依賴這個架構。從心理上來分析,我們是在持續的建設架構中,不需要回避需求的變更,因為我們相信,在需求相對應的迭代中,會繼續對架構進行改進。大家不要認為這種心理的改變是無關緊要的,我起初并沒有意識到這個問題,但是我很快發現新的架構設計過程仍然籠罩在原先的懼怕改變的陰影之下的時候,迭代設計很容易就退化為"Code and Fix"的情形。開發人員難以接受新方法的主要原因還是在心理上。因此,我不得不花了很多的時間來和開發人員進行溝通,這就是我現實的經驗。

  迭代的交錯?
  基于我們對運籌學的一點經驗,迭代設計之間肯定不是線性的關系。這樣說的一個原因架構設計和后續的工作間還是時間差的。因此,我們不會傻到把時間浪費在等待其它工作上。一般而言,當下一次迭代的需求開始之后,詳細需求開始之前,我們就已經可以開始下一次迭代的架構設計了。

  各次迭代之間的時間距離要視項目的具體情況而定。比如,人員比較緊張的項目中,主要的架構設計人員可能也要擔任編碼人員的角色,下一次迭代的架構設計就可能要等到編碼工作的高峰期過了之后。可是,多次的交錯迭代就可能產生版本的問題。比如,本次的迭代的編碼中發現了架構的一個問題,反饋給架構設計組,但是架構設計組已經根據偽修改的本次迭代的架構開始了下一次迭代的架構設計,這時候就會出現不同的設計之間的沖突問題。這種情況當然可以通過加強對設計模型的管理和引入版本控制機制來解決,但肯定會隨之帶來管理成本上升的問題,而這是不符合敏捷的思想的。這時候,團隊設計就體現了他的威力了,這也是我們在團隊設計中沒有提到的一個原因。團隊設計通過完全的溝通,可以解決架構設計中存在沖突的問題。?
  迭代頻率?
  XP提倡迭代周期越短越好(XP建議為一到兩周),這是個不錯的提議。在這么短的一個迭代周期內,我們花在架構設計上的時間可能就只有一兩個小時到半天的時間。這時候,會有一個很有意思的現象,你很難去區分架構設計和設計的概念了。因為在這么短的一個周期之內,完成的需求數量是很少的,可能就只有一兩個用例或用戶素材。因此,這幾項需求的設計是不是屬于架構設計呢?如果是的話,由于開發過程是由多次的迭代組成的,那么開發過程中的設計不都屬于架構設計了嗎?我們說,架構是一個相對的概念,是針對范圍而言的,在傳統的瀑布模型中,我們可以很容易的區分出架構設計和普通設計,如果我們把一次迭代看作是一個單獨的生命周期,那么,普通的設計在這樣一個范圍之內也就是架構設計,他們并沒有什么兩樣。但是,迭代周期中的架構設計是要遵循一定的原則的,這我們在下面還會提到。

  我們希望迭代頻率越快越好,但是這還要根據現實的情況而定。比如數據倉庫項目,在項目的初期階段,我們不得不花費大量的時間來進行數據建模的工作,這其實也是一項專門針對數據的架構設計,建立元數據,制定維,整理數據,這樣子的過程很難分為多次的迭代周期來實現。?
  如何確定軟件的迭代周期?
  可以說,如果一支開發團隊沒有相關迭代的概念,那么這支團隊要立刻實現時隔兩周迭代周期是非常困難的,,同時也是毫無意義的。就像我們在上面討論的,影響迭代周期的因素很多,以至于我們那無法對迭代周期進行量化的定義。因此我們只能從定性的角度分析迭代周期的發展。

  另一個了解迭代的方法是閱讀XP的相關資料,我認為XP中關于迭代周期的使用是很不錯的一種方法,只是他強調的如此短的迭代周期對于很多的軟件團隊而言都是難以實現的。

  迭代周期的引入一定是一個從粗糙到精確的過程。迭代的本質其實是短周期的計劃,因此這也是迭代周期越短對我們越有好處的一大原因,因為時間縮短了,計劃的可預測性就增強了。我們知道,計劃的制定是依賴于已往的經驗,如果原先我們沒有制定計劃或細節計劃的經驗,那么我們的計劃就一定是非常粗糙,最后的誤差也一定很大。但是這沒有關系,每一次的計劃都會對下一次的計劃產生正面的影響,等到經驗足夠的時候,計劃將會非常的精確,最后的誤差也會很小。

  迭代周期的確定需要依賴于單位工作量。單位工作量指的是一定時間內你可以量化的最小的績效。最簡單的單位工作量是每位程序員一天的編碼行數。可惜顯示往往比較殘酷,團隊中不但有程序員的角色,還有設計師、測試人員、文檔制作人員等角色的存在,單純的編碼行數是不能夠作為唯一的統計依據的。同樣,只強調編碼行數,也會導致其它的問題,例如代碼質量。為了保證統計的合理性,比較好的做法是一個團隊實現某個功能所花費的天數作為單位工作量。這里討論的內容實際是軟件測量技術,如果有機會的話,再和大家探討這個問題。?
  迭代周期和軟件架構的改進

  我們應用迭代方法的最大的目的就是為了穩步的改進軟件架構。因此,我們需要了解架構是如何在軟件開發的過程中不斷演進的。在后面的文章中,我們會談到用Refactoring的方法來改進軟件架構,但是Refactoring的定義中強調,Refactoring必須在不修改代碼的外部功能的情況下進行。對于架構來說,我們可以近乎等價的認為就是在外部接口不變的情況下對架構進行改進。而在實際的開發中,除非非常有經驗,否則在軟件開發全過程中保持所有的軟件接口不變是一件非常困難的事情。因此,我們這里談的架構的改進雖然和Refactoring有類似之處,但還是有區別的。

  軟件架構的改進在軟件開發過程會經歷一個振蕩期,這個振蕩期可能橫跨了數個迭代周期,其間架構的設計將會經歷劇烈的變化,但最后一定會取向于平穩。(如果項目后期沒有出現設計平穩化的情況,那么很不幸,你的項目注定要失敗了,要么是時間的問題,要么就是需求的問題)。關鍵的問題在于,我們有沒有勇氣,在架構需要改變的時候就毅然做出變化,而不是眼睜睜的看著問題變得越來越嚴重。最后的例子中,我們討論三個迭代周期,假設我們在第二個周期的時候拒絕對架構進行改變,那么第三個周期一定是有如噩夢一般。變化,才有可能成功。

  我們知道變化的重要性,但沒有辦法知道變化的確切時間。不過我們可以從開發過程中嗅到架構需要變化的氣味:當程序中重復的代碼逐漸變多的時候,當某些類變得格外的臃腫的時候,當編碼人員的編碼速度開始下降的時候,當需求出現大量的變動的時候。
  實例?
  從這一周開始,我和我的小組將要負責對軟件項目中的表示層的設計。在這個迭代周期中,我們的任務是要為客戶端提供6到10個的視圖。由于視圖并不很多,表示層的架構設計非常的簡單:

  準確的說,這里談不上設計,只是簡單讓客戶端訪問不同的視圖而已。當然,在設計的示意圖中,我們并沒有必要畫出所有的視圖來,只要能夠表達客戶端和視圖的關聯性就可以了。

  (架構設計需要和具體的實現綁定,但是在這個例子中,為了著重體現設計的演進,因此把不必要的信息都刪掉。在實際的設計中,視圖可能是JSP頁面,也可能是一個窗口。)

  第一個迭代周的任務很快的完成了,小組負責的表示層模塊也很順利的和其它小組完成了對接,一個簡陋但能夠運轉的小系統順利的發布。客戶觀看了這個系統的演示,對系統提出了修改和補充。

  第二���迭代周中,模塊要處理的視圖增加到了30個,視圖之間存在相同的部分,并且,負責數據層的小組對我們說,由于客戶需求的改進,同一個視圖中將會出現不同的數據源。由于我們的視圖中直接使用了數據層小組提供給我們的數據源的函數,這意味著我們的設計需要進行較大的調整。

  考慮到系統的視圖的量大大的增加,我們有必要對視圖進行集中的管理。前端控制器(Front Control)模式將會是一個不錯的技巧。對于視圖之間的普遍的重復部分,可以將視圖劃分為不同的子視圖,再把子視圖組合為各種各樣的視圖。這樣我們就可以使用組合(Composite)模式:

客戶的請求集中提交給控制器,控制器接受到客戶的請求之后,根據一定的規則,來提供不同的視圖來反饋給客戶。控制器是一個具有擴展能力的設計,目前的視圖數量并不多,因此仍然可以使用控制器來直接分配視圖。如果視圖的處理規則比較復雜,我們還可以使用創建工廠(Create Factory)模式來專門處理生成視圖的問題。對于視圖來說,使用組合模式,把多個不同數據源的視圖組合為復雜的視圖。例如,一個JSP的頁面中,可能需要分為頭頁面和尾頁面。

項目進入第三個迭代周期之后,表示層的需求進一步復雜化。我們需要處理權限信息、需要處理數據的合法性判斷、還需要面對更多的視圖帶來的復雜程度上升的問題。

  表示層的權限處理比較簡單,我們可以從前端控制器中增加權限控制的模塊。同時,為了解決合法性判斷問題,我們又增加了一個數據過濾鏈模塊,來完成數據的合法性判斷和轉換的工作。為了不使得控制器部分的功能過于復雜,我們把原先屬于控制器的視圖分發功能轉移到新的分發器模塊,而控制器專門負責用戶請求、視圖的控制。

我們來回顧這個例子,從迭代周期1中的需求最為簡單,其實,現實中的項目剛開始的需求雖然未必會像例子中的那么簡單,但一定不會過于復雜,因此迭代周期1的設計也非常的簡單。到了迭代周期2的時候,需求開始變得復雜,按照原先的架構繼續設計的話,必然會導致很多的問題,因此對架構進行改進是必要的。我們看到,新的設計能夠滿足新的需求。同樣的,迭代周期3的需求更加的復雜,因此設計也隨之演進。這就是我們在文章的開始提到的"Evolutionary Design"的演進的思想。

架構設計中的方法學(7)——組合使用模式

我們已經討論了敏捷架構設計的4種過程模式,在本文中,我們對這四種過程模式做一個小結,并討論4者間的關系以及體現在模式中的敏捷方法論特色。通過這一章的描述,大家能夠對前面的內容有更進一步的了解。????
???
四種模式的著重點??我把源自需求、團隊設計、簡單設計、迭代設計這4種過程模式歸類為架構設計的第一層次,這4種模式能夠確定架構設計過程的框架。這里需要對框架的含義進行澄清:架構設計的框架并不是說你要嚴格的按照文中介紹的內容來進行架構設計,在文章的一開始我們就指出,模式能夠激發思考。因此,這一框架是需要結合實際,進行改造的。實際,我們在這一個部分中介紹的,比較偏向于原則,我們花了很大的時間來討論原則的來龍去脈,而原則的度,則要大家自己去把握。為什么我們不討論原則的度呢?這里有兩個原因,一個是軟件開發團隊各有特色,很難定義出一個通用的度。第二個原因是我的水平不夠,實踐經驗也不夠豐富。??前面提到的四種模式其實是從四個側面討論了架構設計中的方法問題。源自需求提供了架構設計的基礎。在軟件過程中,架構設計是承接于需求分析的,如果沒有良好的需求分析活動的支持,再好的架構設計也沒有用。因此我們把這一模式放在首位,做為架構設計的目標。??有了確定的目標,還需有組織的保證,這也就是第二種模式――團隊設計的由來。敏捷方法提倡優秀的溝通,因此團隊設計是必要且有效的。而團隊設計的另一個意圖,是保證架構設計的下游活動得以順利的進行,例如詳細設計、編碼、測試等。由于開發團隊中的人大都加入了架構設計,因此最大程度的減小了不同的活動間的信息損耗和溝通效率低下的問題。如果說源自需求模式是起承上的作用,那么團隊設計模式則是扮演了啟下的角色。??在軟件設計的過程中,溝通往往扮演著非常重要的角色。從團隊設計開始的幾種模式所要解決的都是溝通的問題。團隊設計對溝通的貢獻在于它能夠把設計意圖以最小的代價傳播到開發團隊的每個角落。這樣,設計和下游的活動間由于溝通不暢產生的問題就能夠得到緩解。一般而言,設計到編碼會經歷一個信息損失的過程,編碼人員無法正確理解設計人員的意圖,設計人員卻往往無法考慮到一些編碼的細節。雖然我們可以通過共通的設計符號來提高溝通的質量,例如UML。但是實踐證明,只要能夠保證暢通的溝通,即便沒有優秀的開發方法,項目成功的概率依然很高。因此對于單個的項目來說,最關鍵的問題還是在于溝通。只要組織得當,團隊設計是一個值得應用的模式。當然,配合以UML為代表的建模語言,更能夠提高溝通的效果。?
???
??
在設計中,我們發現,當設計信息轉換為編碼信息需要一定的時間,這個時間包括設計的組織時間,設計被理解的時間。如果設計比較復雜,或者說設計的文檔比較復雜,編碼人員花在理解上的時間就會大大增加。因此,權衡后的結果是,相對于詳細的設計說明書而言,簡單的設計說明書再配合一定程度的面對面溝通能夠起到更好的效果。"簡單要比復雜有效",這就是簡單設計模式的基本思路。????
??
同樣,簡單的思路還會用在軟件開發的各個方面,例如文檔、設計、流程。堅持簡單的原則,并不斷的加以改進,是降低軟件開發成本的一種很有效的做法。???
??
在有了以上的思路之后,我們還需要面對兩個現實的問題。需求的變化將會導致設計的不穩定,而需求的復雜性又會導致簡單架構設計的困難。為了解決這個問題,我們引入了迭代的方法,將問題分割為多個子問題(把一個復雜的問題分解為多個較簡單的子問題是計算機領域最常見的處理方法)。這樣,問題的范圍和難度都大大降低了。而更關鍵的是,由于對用戶需求理解不充分或用戶表達需求有錯導致的設計風險被降到最低點。迭代和前面幾個模式都有關系。????
??
需求和迭代????
??
源自需求模式是架構設計中的起手式,沒有這一模式的支持,架構設計只能是空中樓閣。其實,源自需求模式嚴格意義上并不能算是敏捷方法論的特色,而應該算是軟件開發的天然特性。不幸的是,就是這么一個基本的原則,卻沒能夠引起開發者足夠的重視。????
??
敏捷方法論中把需求擺在一個非常重要的位置,我們把源自需求模式作為架構設計的第一個模式,主要的目的是承接架構設計的上游工作――需求。需求決定架構,因此,我們在經典的瀑布模型中可以看到需求到設計的嚴格的分界線,但是在實際的開發中,按照瀑布模型的理論往往會遇到很多的問題,所以,我們嘗試著把需求和(架構)設計之間的界限打破,形成一個重疊的地帶,從而提高軟件開發的速度。因此,我們在源自需求模型中指出,架構設計是緊隨著需求開始的。????
??
需求對軟件開發最具影響就是需求的不穩定性。我們都非常的清楚軟件開發的曲線,越到軟件開發的后期,修改軟件的成本越高。因此,在軟件開發上游的需求的變動將會對軟件開發的下游產生天翻地覆的影響。為了協調這一矛盾,軟工理論提出了螺旋開發模型,這就是我們在迭代開發模式中的討論的理論基礎。把軟件開發過程分為多個的迭代周期,每一次的迭代周期最后都將生成一個可交付的軟件,用戶在每一次的迭代結束后,可以試用軟件,提出下一步的需求或是改變原先的需求。通過這樣的方式,把客戶、開發商的風險降到一個可以接受的水平上。

請注意迭代的前提:需求的易變性。因此,對于那些需求容易發生變化的項目,我們就可以使用迭代式的開發過程,雖然我們會付出一些額外的成本(剛開始這個成本會比較大,但可以用較長的迭代周期來降低這種成本),但是風險減小了。而對于需求比較固定的項目,

是不是有必要使用迭代的方法,就要看具體的環境了。因此,我們是根據實際的情況選用開發方法,而不是因為先進或是流行的原因。

??實際上,由于現代社會的特性,大部分的項目都是可以采用迭代方法。因此,我們的選擇就變成了了迭代周期應該要多長。迭代周期在理論上應該是越短越好,但是并沒有一個絕對的數值,時間的跨度一般從幾周到幾個月。一般來說,迭代周期會受到幾個因素的影響:

??各模塊的關聯程度。在軟件開發中,我們有時候很難把一些模塊分離開來,要開發模塊A,就需要模塊B,而模塊B又需要模塊C。各模塊的關聯程度越高,迭代周期越長。當然,也相應的解決方法,我們可以在各模塊的功能中選取出一些關鍵點,作為里程碑,以里程碑作為迭代完成點。

??人員技能、經驗的平均程度。團隊中成員的開發能力、開發經驗良莠不齊,這也是造成迭代周期延長的一個原因。能力低、經驗少的開發人員會拖后每一次迭代的時間。針對這種情況,做好統籌規劃就顯得非常的重要,可以通過一兩次的迭代,找出隊伍中的瓶頸人員,安排相應的對策。

??工具的缺乏。迭代周期越短,就意味著build、發布的次數越多,客戶也就有更多的機會來修改需求。這要求有相關的工具來幫助開發人員控制軟件。最重要的工具是回歸測試工具。每一次迭代都需要增加新的功能,或是對原先的功能進行改動,這就有可能引入新的bug,如果沒有回歸測試,開發人員就需要花費時間重新測試原先的功能。

計劃、控制的能力。迭代周期越短,所需要的計劃、控制的能力就越強。因為短時間內的計劃制定和實施需要高度的細分,這就要求開發團隊的管理者對開發能力、工作量、任務分配有很強的認識,才能做好這項工作。不過,迭代周期越短,同樣開發時間的迭代次數就越多,而團隊調整、改進計劃控制的機會就越多。因此,后期的迭代一般都能夠做到比較精確的控制。而這樣的做法,要比問題堆積到軟件交付日才爆發出來要好的多。沒有突然落后的軟件,只有每天都在落后的軟件。

??簡單和迭代

??簡單和迭代關系是雙向的。

??在現實設計我們很難界定出簡單設計的程度。怎樣的架構設計才算是簡單?按照我們在簡單設計模式中的討論,剛好滿足目前的需求的架構設計就算是簡單的設計。但是,從另外一個方面考慮,需求的易變性限制我們做出簡單的設計,因為我們不能夠肯定目前的需求將來會發生什么樣的變化。因此,為了克服對未知的恐懼,我們花了很大的力氣設計一些靈活的、能夠適應變化的架構。這是源自需求模式對簡單設計模式的影響。

??源自需求和迭代設計的關系的討論建議我們把需求分為多個迭代周期來實現。那么,相應的架構設計也被分在多個迭代周期中。這樣的方法可以降低架構設計的復雜程度。因為設計人員不需要考慮軟件的全部需求,而只需要考慮當前迭代周期的需求。復雜性的降低將會有助于架構設計的簡單化,從而達到簡單設計的一系列的好處(參見簡單設計)。

??我們從迭代設計中的最后一個例子可以清楚的看到迭代設計是如何把復雜的需求給簡單化的。把握迭代設計有助于我們避免過分設計的毛病。這是個技術人員經常犯的毛病。我所在的團隊很多時候也無法避免。例如,在很多的項目中,我們都會花費大量的時間來設計數據庫到業務實體的映射。諸如此類的技術問題對開發人員的吸引程度是不言而喻的,但是必須看到,這種的設計會導致開發成本的大幅度上升。更為糟糕的是,除非有豐富的經驗,這種類型的設計給開發工作帶來的價值往往無法超過其成本。

??因此,我們需要學會權衡利弊,是否有必要投入大量的資源來開發其實并沒有那么有用的功能。因此,迭代設計和簡單設計的結合有助于我們擺脫過度設計的困擾,把精力集中在真正重要的功能之上。

??此外,簡單的設計并不等同于較少的付出。簡單的設計往往需要對現實世界的抽象,回憶我們在簡單設計中討論的測量模式的例子,它看似簡單,但實現起來卻需要大量的業務知識、很強的設計能力。因此,做到簡單是程序員不斷追尋的目標之一。

??在很多的方法論中,一般并不過分注意代碼重復的問題,要么是不關注,要么認為適當的代碼重復是允許的。而XP卻把代碼重復視為良好代碼的大敵。"只要存在重復代碼,就說明代碼仍有Refactoring的可能。"這種觀點看起來非常的絕對,這可能也正是其名字中Extreme的來歷(英文中的Extreme屬于語氣非常重的一個單詞)。從實踐的角度上來看,追求不重復的代碼雖然很難做到,但是其過程卻可以有效的提高開發團隊代碼的寫作質量,因為它逼迫著你在每次迭代重對代碼進行改進,不能有絲毫的怠惰。而這種迭代的特性,促進了簡單的實現。

??團隊和簡單

??我們在簡單設計中提過簡單設計需要全面的設計師。除此之外,它還需要團隊的配合。簡單意味著不同活動間交付工件的簡單化。也就是說,類似于需求說明書、設計文檔之類的東西都將會比較簡單。正因為如此,我們很難想象一個地理上分布在不同地點的開發團隊或一個超過50人的大團隊能夠利用這種簡單的文檔完成開發任務。

??因此,簡單的設計是需要團隊的組織結構來保證的。簡單的設計要求團隊的相互溝通能夠快速的進行。架構設計完成后,架構的設計思路傳達給所有的編碼人員的速度要塊,同樣,編碼中發現問題,回饋給設計者,設計者經過改進之后再傳達給收到影響的編碼人員的速度也要快。象這樣高效率的傳播我們可以稱之為"Hot Channel"。

??為了保證"Hot Channel"的高溝通效率,最好的組織單位是開發人員在3到6人之間,并處于同間工作室中。這樣的結構可以保證訊息的交互速度達到最高,不需要付出額外的溝通成本,也不需要過于復雜的版本控制工具或權限分配。根據我的經驗,一個共享式的小型版本控制工具、網絡共享、再加上一個簡單的網絡數據庫就能夠解決大部分的問題了。

??在理論上,我們說只要分配得當,大型的團隊同樣可以組織為金字塔式的子團隊,以提高大型團隊的工作效率。但是實際中,隨著團隊的人數的增加,任務的正確分配的���度也隨之加大,溝通信息上傳下達的效率開始下降,子團隊間的隔閡開始出現,各種因素的累加導致敏捷方法并不一定適合于大型的團隊,因此我們討論的敏捷方法都將受到團隊的特性的限制。

模式的源頭

??如果你對XP有一定的了解的話,那么你可能會感覺到我們討論的模式中應用了XP的實踐。確實如此,XP中有很多優秀的實踐,如果組織得當的話,這些微小的實踐將會組合成為一套了不起的開發方法。不過,目前的軟件開發混亂的現狀阻止了先進的軟件方法的應用,對一個身體虛弱的病人施以補藥只會適得其反。因此,在前面討論的模式中,我們應用了一些容易應用、效果明顯的實踐方法。在實踐中適當的應用這些方法,并不需要額外的投入,卻能夠有很好的效果,同時還會為你的團隊打下一個良好的基礎

架構設計中的方法學(8)——架構愿景(2

我們從源自需求模式中,學習到架構的設計是來自于需求的,而應用于軟件全局的架構則來自于最重要的需求。還記得我們在那個模式中提到的網上寵物店的例子嗎?系統采用了MVC模式,sun的官方文檔一開始說明了為什么采用MVC模式,MVC模式解決了什么

問題,然后開始分析MVC模式的幾個組成部分:Model、View、和Controll。其實,MVC中的每一個部分,在真正的代碼中,大都代表了一個子系統,但是在目前,我們就非常的清楚系統大致上會是一個什么樣子,雖然這時候它還十分的朦朧。

不要視圖在全局的架構愿景中就制定出非常細致的規劃,更不要視圖生成大量的實際代碼。因為,你的架構愿景還沒有穩定(我們在其后的穩定化的模式中將會討論穩定的問題),還沒有獲得大家的同意,也沒有經過證明。因此,從整個的開發周期來看,全局架構愿景是隨著迭代周期的進行不斷發展、修改、完善的。

我們如何確定全局架構愿景工作的完成?一般來說,你的架構設計團隊取得了一致的意見就可以結束了,如果問題域是團隊所熟悉的,一兩個小時就能夠解決問題。接下來設計團隊把架構愿景傳播到整個的開發團隊,大家形成一致的認識,不同的意見將會被反饋會來,并在本次的迭代周期(如果時間比較緊迫)或下一次的迭代周期中(如果時間比較寬松)考慮。

子模塊級、或是子問題級的架構愿景

這時候的架構愿景已經是比較明確的了,因為已經存在明確的問題域。例如界面的設計、領域模型的設計、持久層的設計等。這里的愿景制定本質上和全局的愿景制定差不多,具體的例子我們也不再舉了。但是要注意一點,你不能夠和全局愿景所違背。在操作上,全局愿景是設計團隊共同制定出來的,而子模塊級的架構愿景就可以分給設計子團隊來負責,而其審核則還是要設計團隊的共同參與。這有兩個好處,一是確保各個子模塊(子問題)間不至于相互沖突或出現空白地帶,二是每個子設計團隊可以從別人那里吸取設計經驗。

在設計時,同樣我們可以參考其它的資料,例如相關的模式、或規范(界面設計指南)。在一個有開發經驗的團隊,一般都會有開發技術的積累,這些也是可供參考的重要資料。

我們在這個層次的愿景中主要談一談子模塊(子問題)間的耦合問題。一般來說,各個子模塊間的耦合程度相對較小,例如一個MIS系統中,采購和銷售模塊的耦合度就比較小,而子問題間的耦合程度就比較大,例如權限設計、財務,這些功能將會被每個模塊使用。那么,我們就需要為子模塊(子問題)制定出合同接口(Contact Interface)。合同的意思就是說這個接口是正式的,不能夠隨意的修改,因為這個結構將會被其它的設計團隊使用,如果修改,將會對其它的團隊產生無法預計的影響。合同接口的制定、修改都需要設計團隊的通過。此外,系統中的一些全局性的子問題最好是提到全局愿景中考慮,例如在源自需求模式中提到的信貸帳務的例子中,我們就把一個利息計算方式的子問題提到了全局愿景中。

代碼級的愿景

?嚴格的說這一層次的愿景已經不是真正的愿景,而是具體設計了。但是我們為了保證對架構設計理解的完整性,還是簡單的討論一下。這一個層次的愿景一般可以使用類圖、接口來表示。但在類圖中,你不需要標記出具體的屬性、操作,你只需要規定出類的職責以及類之間的相互關系就可以了。該層次愿景的審核需要設計子團隊的通過。

?而設計細分到這個粒度上,執行愿景設計的開發人員可能就只有一兩個左右。但是比較重要的工作在于問題如何分解和如何歸并。分解主要是從兩個維度來考慮,一個是問題大小維,一個是時間長短維。也就是說,你(設計子團隊負責人)需要把問題按大小和解決時間的長短分解為更細的子問題,交給不同的開發人員。然后再把開發人員提出的解決方法組合起來。

??架構愿景的形成過程

架構愿景的形成的源頭是需求,需要特別指出的是,這里的需求主要是那些針對系統基本面的需求。比如說,系統的特點是一個交互式系統,還是一個分布式系統。這些需求將會影響到架構愿景的設計。在收集影響架構愿景的各項需求之后,按照需求的重要性來設計架構愿景。

?架構愿景的設計并不需要很復雜的過程,也不需要花費很多的時間。我們已經提過,架構遠景的主要目的就是為了能夠在開發團隊中傳播設計思路,因此,架構愿景包括基本的設計思路和基本的設計原則。

?值得注意的是,架構遠景可能會有多種的視角,下文討論了一種設計模式的視角。但是實際設計中還可能會基于數據庫來設計架構愿景。但在企業信息系統的設計中,我推薦使用領域類的設計,也就是下文中討論的例子。

架構愿景設計好之后,問題的焦點就轉到如何傳播架構愿景上來,為了達到在開發團隊中取得統一設計意圖的效果,可以考慮援引團隊設計模式。除此之外,針對性的項目前期培訓也會是一種有效的做法。

使用架構模式

架構模式也是一種很好的架構愿景設計思路的來源。隨著對設計模式的研究的深入,人們發現其中的一些設計模式可以擴展、或變化為軟件設計的基礎。在這個基礎上再實現更多的設計,這些模式就形成了架構模式。當然,不同的軟件,它們的架構模式也是不一樣的。在《Applying Pattern》一文中,有一個很典型的架構愿景的例子:

假設我們需要設計分布式的交互式系統。分布式系統和交互式系統都有特定的架構模式,前者為Broker模式,后者為MVC模式。首先我們先要根據系統的特點的重要程度來排列模式的順序。這里假設需求中分布式特性更重要一些。那么我們首先選擇Broker模式作為架構的基本模式:?
???
???
??再考慮交互式的特點,根據MVC模式的特點,我們需要從目前的基本架構中識別出Model、Controller、以及View。Model和View都很簡單,分別分布在上圖中的Server和Client中。而Controller則有兩種的選擇,假設這里的Controller部署在客戶端,上圖則演化為下圖:?
???
???
??這樣,基礎的架構愿景就已經出現了。如果我們還有更多的需求,還可以繼續改進。但是,記住一點,架構愿景不要過于復雜。正如我們在上一節中所討論的,這里我們雖然是基于設計模式來討論架構愿景,但是實際中還有很多從其它的視角來看待架構愿景的。至于要如何選擇架構愿景的視角,關鍵的還是在于需求的理解。

需求分析的20條法��
我們討論的過程僅限于面向對象的軟件開發過程。我們稱之為OOSP(object-oriented?software?process?)。因為我們的過程需要面向對象特性的支持。當然,我們的很多做法一樣可以用在非OO的開發過程中,但是為了達到最佳的效果,我建議您使用OO技術。對商業用戶來說,他們后面是成百上千個供應商,前面是成千上萬個消費顧客。怎樣利用軟件管理錯綜復雜的供應商和消費顧客,如何做好精細到一個小小調料包的進、銷、調、存的商品流通工作,這些都是商業企業需要信息管理系統的理由。軟件開發的意義也就在于此。而弄清商業用戶如此復雜需求的真面目,正是軟件開發成功的關鍵所在。?
  經理:“我們要建立一套完整的商業管理軟件系統,包括商品的進、銷、調、存管理,是總部-門店的連鎖經營模式。通過通信手段門店自動訂貨,供應商自動結算,賣場通過掃條碼實現銷售,管理人員能夠隨時查詢門店商品銷售和庫存情況。另外,我們也得為政府部門提供關于商品營運的報告。”
  分析員:“我已經明白這個項目的大體結構框架,這非常重要,但在制定計劃之前,我們必須收集一些需求。”?
  經理覺得奇怪:“我不是剛告訴你我的需求了嗎?”?
  分析員:“實際上,您只說明了整個項目的概念和目標。這些高層次的業務需求不足以提供開發的內容和時間。我需要與實際將要使用系統的業務人員進行討論,然后才能真正明白達到業務目標所需功能和用戶要求,了解清楚后,才可以發現哪些是現有組件即可實現的,哪些是需要開發的,這樣可節省很多時間。”?
  經理:“業務人員都在招商。他們非常忙,沒有時間與你們詳細討論各種細節。你能不能說明一下你們現有的系統?”?
  分析員盡量解釋從用戶處收集需求的合理性:“如果我們只是憑空猜想用戶的要求,結果不會令人滿意。我們只是軟件開發人員,而不是采購專家、營運專家或是財務專家,我們并不真正明白您這個企業內部運營需要做些什么。我曾經嘗試過,未真正明白這些問題就開始編碼,結果沒有人對產品滿意。”?
  經理堅持道:“行了,行了,我們沒有那么多的時間。讓我來告訴您我們的需求。實際上我也很忙。請馬上開始開發,并隨時將你們的進展情況告訴我。”?
風險躲在需求的迷霧之后?
  以上我們看到的是某客戶項目經理與系統開發小組的分析人員討論業務需求。在項目開發中,所有的項目風險承擔者都對需求分析階段備感興趣。這里所指的風險承擔者包括客戶方面的項目負責人和用戶,開發方面的需求分析人員和項目管理者。這部分工作做得到位,能開發出很優秀的軟件產品,同時也會令客戶滿意。若處理不好,則會導致誤解、挫折、障礙以及潛在的質量和業務價值上的威脅。因此可見——需求分析奠定了軟件工程和項目管理的基礎。?
撥開需求分析的迷霧?
  像這樣的對話經常出現在軟件開發的過程中。客戶項目經理的需求對分析人員來講,像“霧里看花”般模糊并令開發者感到困惑。那么,我們就撥開霧影,分析一下需求的具體內容:
  ·業務需求——反映了組織機構或客戶對系統、產品高層次的目標要求,通常在項目定義與范圍文檔中予以說明。?
  ·用戶需求——描述了用戶使用產品必須要完成的任務,這在使用實例或方案腳本中予以說明。?
  ·功能需求——定義了開發人員必須實現的軟件功能,使用戶利用系統能夠完成他們的任務,從而滿足了業務需求。?
  ·非功能性的需求——描述了系統展現給用戶的行為和執行的操作等,它包括產品必須遵從的標準、規范和約束,操作界面的具體細節和構造上的限制。?
  ·需求分析報告——報告所說明的功能需求充分描述了軟件系統所應具有的外部行為。“需求分析報告”在開發、測試、質量保證、項目管理以及相關項目功能中起著重要作用。?
  前面提到的客戶項目經理通常闡明產品的高層次概念和主要業務內容,為后繼工作建立了一個指導性的框架。其他任何說明都應遵循“業務需求”的規定,然而“業務需求”并不能為開發人員提供開發所需的許多細節說明。?
  下一層次需求——用戶需求,必須從使用產品的用戶處收集。因此,這些用戶構成了另一種軟件客戶,他們清楚要使用該產品完成什么任務和一些非功能性的特性需求。例如:程序的易用性、健壯性和可靠性,而這些特性將會使用戶很好地接受具有該特點的軟件產品。?
  經理層有時試圖代替實際用戶說話,但通常他們無法準確說明“用戶需求”。用戶需求來自產品的真正使用者,必須讓實際用戶參與到收集需求的過程中。如果不這樣做,產品很可能會因缺乏足夠的信息而遺留不少隱患。?
  在實際需求分析過程中,以上兩種客戶可能都覺得沒有時間與需求分析人員討論,有時客戶還希望分析人員無須討論和編寫需求說明就能說出用戶的需求。除非遇到的需求極為簡單;否則不能這樣做。如果您的組織希望軟件成功,那么必須要花上數天時間來消除需求中模糊不清的地方和一些使開發者感到困惑的方面。?
  優秀的軟件產品建立在優秀的需求基礎之上,而優秀的需求源于客戶與開發人員之間有效的交流和合作。只有雙方參與者都明白自己需要什么、成功的合作需要什么時,才能建立起一種良好的合作關系。?
  由于項目的壓力與日俱增,所有項目風險承擔者有著一個共同目標,那就是大家都想開發出一個既能實現商業價值又能滿足用戶要求,還能使開發者感到滿足的優秀軟件產品。?
客戶的需求觀?
  客戶與開發人員交流需要好的方法。下面建議20條法則,客戶和開發人員可以通過評審以下內容并達成共識。如果遇到分歧,將通過協商達成對各自義務的相互理解,以便減少以后的磨擦(如一方要求而另一方不愿意或不能夠滿足要求)。?
1、 分析人員要使用符合客戶語言習慣的表達?
  需求討論集中于業務需求和任務,因此要使用術語。客戶應將有關術語(例如:采價、印花商品等采購術語)教給分析人員,而客戶不一定要懂得計算機行業的術語。?
2、分析人員要了解客戶的業務及目標?
  只有分析人員更好地了解客戶的業務,才能使產品更好地滿足需要。這將有助于開發人員設計出真正滿足客戶需要并達到期望的優秀軟件。為幫助開發和分析人員,客戶可以考慮邀請他們觀察自己的工作流程。如果是切換新系統,那么開發和分析人員應使用一下目前的舊系統,有利于他們明白目前系統是怎樣工作的,其流程情況以及可供改進之處。s?3、分析人員必須編寫軟件需求報告?
  分析人員應將從客戶那里獲得的所有信息進行整理,以區分業務需求及規范、功能需求、質量目標、解決方法和其他信息。通過這些分析,客戶就能得到一份“需求分析報告”,此份報告使開發人員和客戶之間針對要開發的產品內容達成協議。報告應以一種客戶認為易于翻閱和理解的方式組織編寫。客戶要評審此報告,以確保報告內容準確完整地表達其需求。一份高質量的“需求分析報告”有助于開發人員開發出真正需要的產品。?
4、 要求得到需求工作結果的解釋說明?
  分析人員可能采用了多種圖表作為文字性“需求分析報告”的補充說明,因為工作圖表能很清晰地描述出系統行為的某些方面,所以報告中各種圖表有著極高的價值;雖然它們不太難于理解,但是客戶可能對此并不熟悉,因此客戶可以要求分析人員解釋說明每個圖表的作用、符號的意義和需求開發工作的結果,以及怎樣檢查圖表有無錯誤及不一致等。?
5、 開發人員要尊重客戶的意見?
  如果用戶與開發人員之間不能相互理解,那關于需求的討論將會有障礙。共同合作能使大家“兼聽則明”。參與需求開發過程的客戶有權要求開發人員尊重他們并珍惜他們為項目成功所付出的時間,同樣,客戶也應對開發人員為項目成功這一共同目標所做出的努力表示尊重。?
6、 開發人員要對需求及產品實施提出建議和解決方案?
  通常客戶所說的“需求”已經是一種實際可行的實施方案,分析人員應盡力從這些解決方法中了解真正的業務需求,同時還應找出已有系統與當前業務不符之處,以確保產品不會無效或低效;在徹底弄清業務領域內的事情后,分析人員就能提出相當好的改進方法,有經驗且有創造力的分析人員還能提出增加一些用戶沒有發現的很有價值的系統特性。?
7、 描述產品使用特性?
  客戶可以要求分析人員在實現功能需求的同時還注意軟件的易用性,因為這些易用特性或質量屬性能使客戶更準確、高效地完成任務。例如:客戶有時要求產品要“界面友好”或“健壯”或“高效率”,但對于開發人員來講,太主觀了并無實用價值。正確的做法是,分析人員通過詢問和調查了解客戶所要的“友好、健壯、高效所包含的具體特性,具體分析哪些特性對哪些特性有負面影響,在性能代價和所提出解決方案的預期利益之間做出權衡,以確保做出合理的取舍。?
8、 允許重用已有的軟件組件?
  需求通常有一定靈活性,分析人員可能發現已有的某個軟件組件與客戶描述的需求很相符,在這種情況下,分析人員應提供一些修改需求的選擇以便開發人員能夠降低新系統的開發成本和節省時間,而不必嚴格按原有的需求說明開發。所以說,如果想在產品中使用一些已有的商業常用組件,而它們并不完全適合您所需的特性,這時一定程度上的需求靈活性就顯得極為重要了。?
9、 要求對變更的代價提供真實可靠的評估?
  有時,人們面臨更好、也更昂貴的方案時,會做出不同的選擇。而這時,對需求變更的影響進行評估從而對業務決策提供幫助,是十分必要的。所以,客戶有權利要求開發人員通過分析給出一個真實可信的評估,包括影響、成本和得失等。開發人員不能由于不想實施變更而隨意夸大評估成本。?
10、 獲得滿足客戶功能和質量要求的系統?
  每個人都希望項目成功,但這不僅要求客戶要清晰地告知開發人員關于系統“做什么”所需的所有信息,而且還要求開發人員能通過交流了解清楚取舍與限制,一定要明確說明您的假設和潛在的期望,否則,開發人員開發出的產品很可能無法讓您滿意。?
11、 給分析人員講解您的業務?
  分析人員要依靠客戶講解業務概念及術語,但客戶不能指望分析人員會成為該領域的專家,而只能讓他們明白您的問題和目標;不要期望分析人員能把握客戶業務的細微潛在之處,他們可能不知道那些對于客戶來說理所當然的“常識”。?
12、 抽出時間清楚地說明并完善需求?
  客戶很忙,但無論如何客戶有必要抽出時間參與“頭腦高峰會議”的討論,接受采訪或其他獲取需求的活動。有些分析人員可能先明白了您的觀點,而過后發現還需要您的講解,這時請耐心對待一些需求和需求的精化工作過程中的反復,因為它是人們交流中很自然的現象,何況這對軟件產品的成功極為重要。?
13、 準確而詳細地說明需求?
  編寫一份清晰、準確的需求文檔是很困難的。由于處理細節問題不但煩人而且耗時,因此很容易留下模糊不清的需求。但是在開發過程中,必須解決這種模糊性和不準確性,而客戶恰恰是為解決這些問題作出決定的最佳人選,否則,就只好靠開發人員去正確猜測了。?
  在需求分析中暫時加上“待定”標志是個方法。用該標志可指明哪些是需要進一步討論、分析或增加信息的地方,有時也可能因為某個特殊需求難以解決或沒有人愿意處理它而標注上“待定”。客戶要盡量將每項需求的內容都闡述清楚,以便分析人員能準確地將它們寫進“軟件需求報告”中去。如果客戶一時不能準確表達,通常就要求用原型技術,通過原型開發,客戶可以同開發人員一起反復修改,不斷完善需求定義。?
14、 及時作出決定?
  分析人員會要求客戶作出一些選擇和決定,這些決定包括來自多個用戶提出的處理方法或在質量特性沖突和信息準確度中選擇折衷方案等。有權作出決定的客戶必須積極地對待這一切,盡快做處理,做決定,因為開發人員通常只有等客戶做出決定才能行動,而這種等待會延誤項目的進展。?
15、 尊重開發人員的需求可行性及成本評估?
  所有的軟件功能都有其成本。客戶所希望的某些產品特性可能在技術上行不通,或者實現它要付出極高的代價,而某些需求試圖達到在操作環境中不可能達到的性能,或試圖得到一些根本得不到的數據。開發人員會對此作出負面的評價,客戶應該尊重他們的意見。
16、 劃分需求的優先級?
  絕大多數項目沒有足夠的時間或資源實現功能性的每個細節。決定哪些特性是必要的,哪些是重要的,是需求開發的主要部分,這只能由客戶負責設定需求優先級,因為開發者不可能按照客戶的觀點決定需求優先級;開發人員將為您確定優先級提供有關每個需求的花費和風險的信息。?
  在時間和資源限制下,關于所需特性能否完成或完成多少應尊重開發人員的意見。盡管沒有人愿意看到自己所希望的需求在項目中未被實現,但畢竟是要面對現實,業務決策有時不得不依據優先級來縮小項目范圍或延長工期,或增加資源,或在質量上尋找折衷。?
17、 評審需求文檔和原型?
  客戶評審需求文檔,是給分析人員帶來反饋信息的一個機會。如果客戶認為編寫的“需求分析報告”不夠準確,就有必要盡早告知分析人員并為改進提供建議。?
  更好的辦法是先為產品開發一個原型。這樣客戶就能提供更有價值的反饋信息給開發人員,使他們更好地理解您的需求;原型并非是一個實際應用產品,但開發人員能將其轉化、擴充成功能齊全的系統。?
18、 需求變更要立即聯系?
  不斷的需求變更,會給在預定計劃內完成的質量產品帶來嚴重的不利影響。變更是不可避免的,但在開發周期中,變更越在晚期出現,其影響越大;變更不僅會導致代價極高的返工,而且工期將被延誤,特別是在大體結構已完成后又需要增加新特性時。所以,一旦客戶發現需要變更需求時,請立即通知分析人員。?
19、 遵照開發小組處理需求變更的過程?
  為將變更帶來的負面影響減少到最低限度,所有參與者必須遵照項目變更控制過程。這要求不放棄所有提出的變更,對每項要求的變更進行分析、綜合考慮,最后做出合適的決策,以確定應將哪些變更引入項目中。?
20、 尊重開發人員采用的需求分析過程?
  軟件開發中最具挑戰性的莫過于收集需求并確定其正確性,分析人員采用的方法有其合理性。也許客戶認為收集需求的過程不太劃算,但請相信花在需求開發上的時間是非常有價值的;如果您理解并支持分析人員為收集、編寫需求文檔和確保其質量所采用的技術,那么整個過程將會更為順利。?
“需求確認”意味著什么?
  在“需求分析報告”上簽字確認,通常被認為是客戶同意需求分析的標志行為,然而實際操作中,客戶往往把“簽字”看作是毫無意義的事情。“他們要我在需求文檔的最后一行下面簽名,于是我就簽了,否則這些開發人員不開始編碼。”?
  這種態度將帶來麻煩,譬如客戶想更改需求或對產品不滿時就會說:“不錯,我是在需求分析報告上簽了字,但我并沒有時間去讀完所有的內容,我是相信你們的,是你們非讓我簽字的。”?
  同樣問題也會發生在僅把“簽字確認”看作是完成任務的分析人員身上,一旦有需求變更出現,他便指著“需求分析報告”說:“您已經在需求上簽字了,所以這些就是我們所開發的,如果您想要別的什么,您應早些告訴我們。”?
  這兩種態度都是不對的。因為不可能在項目的早期就了解所有的需求,而且毫無疑問地需求將會出現變更,在“需求分析報告”上簽字確認是終止需求分析過程的正確方法,所以我們必須明白簽字意味著什么。?
  對“需求分析報告”的簽名是建立在一個需求協議的基線上,因此我們對簽名應該這樣理解:“我同意這份需求文檔表述了我們對項目軟件需求的了解,進一步的變更可在此基線上通過項目定義的變更過程來進行。我知道變更可能會使我們重新協商成本、資源和項目階段任務等事宜。”對需求分析達成一定的共識會使雙方易于忍受將來的摩擦,這些摩擦來源于項目的改進和需求的誤差或市場和業務的新要求等。?
  需求確認將迷霧撥散,顯現需求的真面目,給初步的需求開發工作畫上了雙方都明確的句號,并有助于形成一個持續良好的客戶與開發人員的關系,為項目的成功奠定了堅實的基礎。


專訪架構師周愛民:談企業軟件架構設計

最近在網上讀到了“殺不死的人狼——我讀《人月神話》”系列文章。是周愛民關于《人月神化》的讀書心得。《人月神化》在軟件工程里一本很有分量的書,講述了Brooks博士在IBM公司 System/360家族和OS/360中的項目管理經驗。周愛民在他的這一系列文章中用自己架構師經歷為基礎,從他的視角重新品讀了這本書。而這也使我有了采訪下他的想法,從中我們也許可以了解到中國企業內軟件架構設計這個環節的現狀。目前周愛民是盛大網絡架構師。在此特別感謝周愛民在百忙中抽出時間回復了這次訪談。

?1, 您好,請先向我們的網友簡單做一下自我介紹自己好嗎?

我94年開始學習電腦,基本上從一開始就學編程。從96年開始涉及商業軟件開發,到現在約十一年了。其間我在鄭州的一家軟件公司呆了7年,歷經了一家軟件公司的中興到消亡,因而也意識到工程、管理在軟件企業——當然也包括其它類型的企業——中的價值。后來,從03年開始的一年多時間,我在鄭州的另一家公司任軟件部經理,也開始實踐自己的工程和管理思想。很好,到現在我離開這家公司一年多了,公司狀況依然很不錯。我認為,團隊或公司并沒有因為你的缺席而變得糟糕,那便已經是良性管理的表現了。關于“Borland Delphi產品專家”,其實更多的是一個圈子的認可,而非行業的認可。我在“大富翁論壇(delphibbs.com)”活動了很長的時間,得到了一些朋友們的認可,后來Borland要評選這個專家的時候,大家推舉了我,于是就得了這個稱號。其實在我看來,優秀的人才、專家很多,我大約是人緣好點,運氣好點罷。

我05年9月開始到盛大網絡,任架構師一職。當時Borland China也有offer,但在顧問、軟件工程師與架構師之間,我選擇了架構師這個職務,因為我對這個角色更加感興趣。我目前的工作,主要是盛大的軟件平臺方面的架構、設計和一些實施方面的事務。雖然很多人認為盛大是做游戲的公司,但我基本不涉及游戲產品的開發。

在開發技術方面,我03年出版過一本《Delphi源代碼分析》。在工程方面,《大道至簡——軟件工程實踐者的思想》一書在下月初就應出版了,它的第一版是以電子版的形式發布的。我在寫的第三本書則是講計算機語言的,題材是“動態函數式語言”。

?2,您做為盛大網絡的架構師,請介紹一下在軟件項目中平臺架構師是一份怎樣的角色?主要處理哪些工作?

架構師有很多種。很多人把體系架構師與架構師等同,其實不對。各類架構師基本素質要求大抵一致,例如分析能力、設計的技術方法,以及對設計目標的前瞻性。但是他們的專業素質會有一些差別。舉個實例來說,如果讓我設計游戲引擎的架構,我就會做不好。但是,如果這個游戲引擎要設計成一個獨立的平臺層次,具有語言無關性、平臺整合能力,或是對不同類型游戲的統一支撐,那么就是平臺架構師的職責了。

具體來說,平臺架構師會決策某個部分與其它部分的相互關系、界面的規約和檢測評估它們的方法。如果一個游戲引擎只為某個游戲而設計,那么是用不到平臺架構師的。但如果A游戲中的引擎要移植到B游戲,或者更多的游戲,甚至只是抽離它的部分,以作為某種體系中的一個數據交互層,那么就需要平臺架構師來考量技術上的可行性、穩定性以及它對于更大范圍內的平臺建設的價值——當然,如果沒有價值,架構師也會否定它。

平臺是長期建設的。平臺架構師的重要職責之一,就是長期的規劃和持續的推進。所以平臺架構師的工作總是伴隨客戶的戰略決策的。如果一個設計只是解決短期的技術問題,那么也并不需要平臺架構師,但如果是幾年或十幾年要在上面持續經營的一個整體方向,那么平臺架構師就需要圍繞戰略來設計架構的藍圖,并決定規劃的實施步驟。在這些方面,他可能需要協調很多團隊一些來工作。不過,這可不是跟項目經理搶飯碗。因為項目經理重在實施,而架構師重在規劃。

當然,事實上我也做一些其它類型的架構設計工作。例如設計一個小的模塊,或者一個業務工件。好的架構師不會拒絕這些工作,而是從更多的、細節的工作中發現整體與局部的關系。也只有觸及到具體工作的細節,架構師才可能更早地發覺設計上的隱患或者與目標的偏差。

?3,《人月神話》這本書30多年來一直被認為是項目管理者的必讀書,最近也看到您的blog里寫了一系列相關的書評。您是怎么看到書中“項目實施法則“和實際項目工作之間的關系。

這幾個問題我基本上都在《殺不死的人狼》一文中講過了。概括來說,我認為有以下三點:

一、討論“有或沒有”銀彈這樣的話題沒有意義,因為《人月神話》所述的人狼根本殺不死,而且Brooks所設想的銀彈也過于學術。
二、《人月神話》從廣義工程的角度設定了這個命題,這個命題的根本目標與次要目標正好與具體工程(狹義工程)相反。
三、我承認《人月神話》神話所述的答案以及建議在如今的軟件工程中得到了體現。但我們應該更清醒地辨析出現象、答案與本質,并分析哪些是本質的自然延伸,而哪些只是《人月神話》所帶來的影響——Brooks預言了未來,也就改變了未來,即使未來未必應該如此。


與大多數人不一樣的是,我更多的是從與Brooks的預言不一致的那些現象是去發現一些東西。我所看到的是,正是在改變了Brooks的命題,或者認識到他所述的“本質”未必正確的時候,我們才找到了一些“不一樣的成功”。我提醒大家關注這些事例,以及它們與傳統工程、廣義工程的本質差異。

我并不反對《人月神話》中的大多數工程觀點,以及我們現在的軟件業中的工程實踐經驗。但是狹義工程沒有必要去追尋銀彈或那些看起來看銀彈的東西,我們應該更加靈活。

4企業在進行項目的軟件架構設計時,需要考慮哪些關鍵的問題?

企業實施過程中的架構問題,可以分成兩個部分來考慮。一個是軟件企業自身,一個是工程的目標客戶(有些時候它與前者一則)。基本上來說,架構設計首先是面向客戶的,甚至在整個工程的絕大多數時候都面向客戶。因為理解決定設計,所以讓架構師盡可能早地、深入地了解工程目標、應用環境、戰略決策和發展方向,是至關重要的。否則,架構師是不可能做出有效的設計來的。

架構設計關注于三個方面:穩定、持續和代價。

穩定性由架構師的設計能力決定。架構的好壞是很難評判的,但基本的法則是“適用”。如果一個架構不適用,那么再小或者再大都不可能穩定。所因此進一步推論是“架構必須以工程的主體目標為設計象”。看起來這是個簡單的事,但事實上很多架構設計中只是在做邊角功夫,例如為一兩處所謂的“精彩的局部”而叫好,全然不顧架構是否為相應的目標而做。

持續性由架構師的地位決定。如果不能認識“設計的一致性”,以及架構師對這種一致性的權威,那么再好的架構也會面臨解體,再長遠的架構也會在短期內被廢棄。架構的實施是要以犧牲

自由性為代價的,架構師沒有足夠的地位(或權威),則不可能對抗實施者對自由的渴望。通常的失敗,并在于架構的好或壞,而是架構被架空,形同虛設。

代價的問題上面有過一點討論,但方向不同。這里說明的是,如果架構師沒有充分的經驗,不能準確評估所設計的架構的資源消耗,那么可能在項目初起便存在設計失誤;也可能在項目中困于枝節,或疏離關鍵,從而徒耗了資源。這些都是架構師應該預見、預估的。

對于企業設計來說,上面三個方面沒有得到關注的結果就是:遲遲無法上線的工程、半拉子工程和不停追加投資的工程項目。我不否認項目經理對這些問題的影響,但事實上可能從設計就開始出了問題,而項目經理只是回天乏術罷了。

最后說明一下,我認為目前大多數的企業項目都缺乏架構上的考量。大多數軟件公司只是出于自身的需要(例如組件化和規模開發)而進行架構設計。這樣的設計不是面向客戶的,事實上這增加了客戶投資,而未能給客戶項目產生價值。這也是我強調架構面向客戶的原因之一。

?

5? 目前,你的團隊在使用什么樣的產品或者方法來進行軟件架構設計?

架構設計的主要輸出是文檔,因而并沒有什么特別的工具來幫助你做架構設計。很多工具是輔助分析的,例如MindMananger;另外一些則可能輔助你表述,例如Together和Rose。

大多數技術出身的架構師會僅把“軟件編寫的東西”才稱為工具。其實不然,會議室里的那面白板也是我的工具之一。放開思路,市場規劃圖、技術架構路標圖、特性/收益規劃圖等等這些圖表也是我們的工具。除開這些之外,模式語言和建模語言也是主要的、形式化的工具。

我經常按RUP的規范寫文檔,也偶爾放棄其中的某些具體格式。這些既有的文檔模板也是工具。當然,毋庸置疑的是這樣的工具也包括WORD和PowerPoint——很多人并不知道,我有1/4的設計是先用PowerPoint/Visio來完成的。

具體到方法,則非常多了,但應用哪一種則與場景有關。不過最先做的則是分層,這與自頂向下的結構分析很象——事實上在分析和設計的最初階段,這種方法幾乎是必須的。


6,您覺得國內外軟件架構設計這個環節的主要不同在哪里?

正如你這個問題所表現出來的一樣:我們太注重于工程環節的某個局部。

國外軟件行業在工程實踐經驗上已豐富得多,因此大多數程序員、項目經理或測試人員等等對工程的理解也深刻得多。他們并不自恃于當前的環節,也不否認其它環節。這意味著在整體實施

中大家更容易達成一致。然而國內的軟件工程則很少強調這種合作,項目經理強調管理,程序員強調技術,架構師強調一致性和持續性,測試人員則很開心的看到每一個錯誤并以及數量作為評核依據。

顯然這里出了問題:我們的合作環節在各自為戰。大家都在強調自己的重要性,于是工程就沒法做了。解決的法子,還是讓大家都意識到對方工作的目標與職責,而不僅僅是了解自己的那個小圈子。

?
7,可以介紹一下你目前的Qomo項目嗎?我們的網友該如何參與?

Qomo(Qomolangma OpenProject)是一個JavaScript上的開源項目。目前Qomo 1.0正式版已經發布了。Qomo V1以語言補實為基本思想,在JavaScript上擴展了AOP、OOP、IOP和GP等編程方法,基于它自身的完備的實現,Qomo也提供了Builder和Profiler工具和相關的庫。

Qomo V1只是整個Qomolangma OpenProject構想中的一很小一部分——盡管它重要。Qomo項目提出的整體目標是:
 -Qomo內核是足夠強大的能應用在不同的JavaScript宿主環境下的通用擴展。
 -Qomo有能力提供膠合不同的應用環境下功能需求的中間代碼。
 -Qomo可以作為定制的宿主應用的代碼包的一個部分以提升應用的體驗或局部性能。

所以Qomo V1并不完備。即便是我們正在展開的Qomo V2,也并不完備。V2計劃提供組件庫、數據庫存取層和圖形表現層。此外,Qomo V2也打算啟用數個實踐項目,一方面作為Qomo的范例,另一方面也驗證Qomo的設計。

Qomo已經在sourceforge上注冊過,但在那里表現并不活躍。你可以總是從我的blog上得到Qomo的最新消息,包括Qomo的計劃與每個版本發布。至于參與這個項目,請發mail給我。



C++之設計模式實現代碼

----------------------- Page 1-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????????????????http://www.mscenter.edu.cn/blog/k_eckel

??? 設計模式精解-GoF 23 種設計模式解析附 C++實現源碼

???????????????????????????????????????????????????????????????? 目??????????? 錄

0?? 引言..............................................................................................................................................2
??????? 0.1 設計模式解析(總序).....................................................................................................2
??????? 0.2 設計模式解析后記.............................................................................................................2
??????? 0.3?? 與作者聯系........................................................................................................................5
1? 創建型模式...................................................................................................................................5
??????? 1.1 Factory模式 ........................................................................................................................5
??????? 1.2 AbstactFactory模式 .......................................................................................................... 11
??????? 1.3 Singleton模式...................................................................................................................16
??????? 1.4 Builder模式.......................................................................................................................18
??????? 1.5 Prototype模式...................................................................................................................23
2?? 結構型模式.................................................................................................................................26
?????? 2.1 Bridge模式........................................................................................................................26
?????? 2.2 Adapter模式......................................................................................................................31
?????? 2.3 Decorator模式...................................................................................................................35
?????? 2.4 Composite模式.................................................................................................................40
?????? 2.5 Flyweight模式 ..................................................................................................................44
?????? 2.6 Facade模式.......................................................................................................................49
?????? 2.7 Proxy模式.........................................................................................................................52
3?? 行為模式.....................................................................................................................................55
??????? 3.1 Template模式....................................................................................................................55
??????? 3.2 Strategy模式 .....................................................................................................................59
??????? 3.3 State模式...........................................................................................................................63
??????? 3.4 Observer模式....................................................................................................................68
??????? 3.5 Memento模式...................................................................................................................73
??????? 3.6 Mediator模式....................................................................................................................76
??????? 3.7 Command模式..................................................................................................................81
??????? 3.8 Visitor模式........................................................................................................................87
??????? 3.9 Chain of Responsibility模式.............................................................................................92
??????? 3.10 Iterator模式.....................................................................................................................96
??????? 3.11 Interpreter模式..............................................................................................................100
4?? 說明 ..........................................................................................................................................105

????????????????????????????????????????????????????????? 第? 1??? 頁 共? 105??????? 頁??????????????????????????????????????????????????? k_eckel

----------------------- Page 2-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

0?? 引言

0.1 設計模式解析(總序)

???? “Next to My Life, Software Is My Passion”——Robert C.Martin.

??? 懂了設計模式,你就懂了面向對象分析和設計(OOA/D )的精要。反之好像也可能成

立。道可道,非常道。道不遠人,設計模式亦然如此。

??? 一直想把自己的學習經驗以及在項目中的應用經歷拿出來和大家共享,卻總是下不了這

個決心:GoF 的23 種模式研讀、總結也總需要些時日,然而時間對于我來說總是不可預計

的。

??? 之所以下了這個決心,有兩個原因:一是Robert 的箴言,二是因為我是一個感恩的人,

就像常說的:長懷感恩之心,人生便無遺憾。想想當時讀 GoF? 的那本圣經時候的苦悶、實

現23 個模式時候的探索、悟道后的欣悅,我覺得還是有這個意義。

0.2 設計模式解析后記

??? 寫完了Interpreter模式之后,我習慣性的看看下一天的安排,卻陡然發現GoF的 23個

設計模式的解析已經在我不經意間寫完了。就像在一年前看GoF的《設計模式》一書,和半

年前用C++模擬、實現 23種經典的設計模式一般,透過這個寫解析的過程,我又看到了另外

一個境界。一直認為學習的過程很多時候可以這樣劃分:自己學會一門知識(技術)、表達

出來、教會別人、記錄下來,雖然這個排序未必對每個人都合適 (因為可能不同人有著不同

的特點能力)。學一門知識,經過努力、加以時日,總是可以達到的,把自己學的用自己的

話表達出來就必須要將學到的知識加以消化、理解,而教會一個不懂這門知識的人則比表達

出來要難,因為別人可能并不是適應你的表述方式,記錄下來則需要經過沉淀、積累、思考,

最后厚積薄發,方可小成。?

??? 設計模式之于面向對象系統的設計和開發的作用就有如數據結構之于面向過程開發的

作用一般,其重要性和必要性自然不需要我贅述。然而學習設計模式的過程卻是痛苦的,從

閱讀設計模式的圣經——GoF 的《設計模式:可復用面向對象軟件的基礎》時的枯燥、苦悶、

茫無頭緒,到有一天突然有一種頓悟;自己去實現GoF 的23 中模式時候的知其然不知其所

以然,并且有一天在自己設計的系統種由于設計的原因讓自己苦不堪言,突然悟到了設計模

????????????????????????????? 第? 2 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 3-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

式種的某一個正好可以很好的解決問題,到自己設計的 elegant 的系統時候的喜悅與思考;

一直到最后向別人去講解設計模式,別人向你咨詢設計模式,和別人討論設計模式。就如

GoF 在其前言中說到:一旦你理解了設計并且有了一種 “Aha!” (而不是 “Huh?”)的應

用經驗和體驗后,你將用一種非同尋常的方式思考面向對象設計。這個過程我認為是漫長的,

painful,但是是非常必要的。經過了的才是自己的,Scott Mayer 在其巨著《Effective C++》

就曾經說過:C++老手和C++新手的區別就是前者手背上有很多傷疤。是的在軟件開發和設

計的過程中,失敗、錯誤是最好的老師,當然在系統開發中,失敗和錯誤則是噩夢的開端和

結束,因為你很難有改正錯誤的機會。因此,盡量讓自己多幾道疤痕是對的。?

??? 面向對象系統的分析和設計實際上追求的就是兩點,一是高內聚 (Cohesion),而是低

耦合 (Coupling)。這也是我們軟件設計所準求的,因此無論是OO 中的封裝、繼承、多態,

還是我們的設計模式的原則和實例都是在為了這兩個目標努力著、貢獻著。?

??? 道不遠人,設計模式也是這般,正如我在 《設計模式探索(總序)》中提到的。設計模

式并不是空的理論,并不是脫離實際的教條。就如我們在進行軟件開發的過程會很自然用到

很多的算法和結構來解決實際的問題,那些其實也就是數據結構中的重要概念和內容。在面

向對象系統的設計和開發中,我們已經積累了很多的原則,比如面向對象中的封裝、繼承和

多態、面向接口編程、優先使用組合而不是繼承、將抽象和實現分離的思想等等,在設計模

式中你總是能看到他們的影子,特別是組合 (委托)和繼承的差異帶來系統在耦合性上的差

別,更是在設計模式多次涉及到。而一些設計模式的思想在我們做系統的設計和開發中則是

經常要用到的,比如說Template、Strategy模式的思想,Singleton模式的思想,Factory

模式的思想等等,還有很多的模式已經在我們的開發平臺中扎根了,比如說Observer (其實

例為Model-Control-View模式)是MFC和Struts中的基本框架,Iterator模式則在C++的STL

中有實現等。或許有的人會說,我們不需要設計模式,我們的系統很小,設計模式會束縛我

們的實現。我想說的是,設計模式體現的是一種思想,而思想則是指導行為的一切,理解和

掌握了設計模式,并不是說記住了23種(或更多)設計場景和解決策略(實際上這也是很

重要的一筆財富),實際接受的是一種思想的熏陶和洗禮,等這種思想融入到了你的思想中

后,你就會不自覺地使用這種思想去進行你的設計和開發,這一切才是最重要的。?

??? 之于學習設計模式的過程我想應該是一個迭代的過程,我向來學東西的時候不追求一遍

就掌握、理解透徹 (很多情況也是不可能的),我喜歡用一種迭代的思想來指導我的學習過

程。看書看不懂、思想沒有理解,可以反復去讀、去思考,我認為這樣一個過程是適合向我

們不是有一個很統一的時間去學習一種技術和知識(可能那樣有時候反而有些枯燥和郁悶)。

????????????????????????????? 第? 3 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 4-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

GoF 在 《設計模式》一書中也提到,如果不是一個有經驗的面向對象設計人員,建議從最簡

單最常用的設計模式入門,比如AbstractFactory 模式、Adapater模式、Composite 模式、

Decorator 模式、Factory模式、Observer模式、Strategy 模式、Template 模式等。我的

感觸是確實是這樣,至少GoF 列出的模式我都在開發和設計有用到,如果需要我這里再加上

幾個我覺得在開發中會很有用的模式:Singleton模式、Fa?ade模式和Bridge 模式。?

??? 寫設計模式解析的目的其實是想把GoF 的《設計模式》進行簡化,變得容易理解和接受。

GoF 的 《設計模式》是圣經,但是同時因為 《設計模式》一書是4 位博士的作品,并且主要

是基于Erich 的博士論文,博士的特色我覺得最大的就是抽象,將一個具體的問題抽象到一

般,形成理論。因此GoF 的這本圣經在很多地方用語都比較精簡和抽象,讀過的可能都有一

種確實是博士寫出來的東西的感覺。抽象的好處是能夠提供指導性的意見和建議,其瑕疵就

是不容易為新手所理解和掌握。我的本意是想為抽象描述和具體的實現提供一個橋接 (盡管

GoF 在書中給出了很多的代碼和實例,但是我覺得有兩個不足:一是不完整,結果是不好直

接看到演示,因此我給出的代碼都是完整的、可編譯運行的;二是給出的都是一些比較大的

系統中一部分簡單實現,我想GoF 的原意可能是想說明這些模式確實很管用,但是卻同時帶

來一個更大的不好的地方就是不容易為新手理解和掌握),然而這個過程是痛苦的,也可能

是不成功的 (可能會是這樣)。這里面就有一個取舍的問題,一方面我想盡量去簡化GoF

的描述,然而思考后的東西卻在很多的時候和GoF 的描述很相似,并且覺得將這些內容再抽

象一下,書中的很多表達則是最為經典的。當然這里面也有些許的例外,Bruce Eckel 在其

大作《Thinking in Patterns》一書中提到:Bridge 模式是GoF 在描述其 23 中設計模式中

描述得最為糟糕得模式,于我心有戚戚焉!具體的內容請參看我寫的《設計模式解析——

Bridge 模式》一文。另外一方面,我又要盡量去避免走到了GoF 一起,因為那樣就失去了

我寫這個解析的本意了。這兩個方面的權衡是很痛苦,并且結果可能也還是沒有達到我的本

意要求。?

??? 4 月份是我最不忙的時候,也是我非常忙的時候。論文的查閱、思考、撰寫,幾個項目

的前期準備 (文檔、Demo等),俱樂部的諸多事宜,挑戰杯的準備,學習 (課業、專業等各

個方面)等等,更加重要的是Visual CMCS????????????? (Visual C_minus Compiler System)的設

計和開發(Visual CMCS是筆者設計和開發的C_minus語言(C的子集)的編譯系統,系統操

作界面類似VC,并且準備代碼分發和共享,詳細信息請參考Visual CMCS的網站和Blog中的

相關信息的發布), Visual CMCS1.0(Beta)終于在4 月底發布了,也在別人的幫助下構建

?????????????????? http://cs.whu.edu.cn/cmcs )。之所以提及這個,一方面是在Visual CMCS
了Visual CMCS的網站(

????????????????????????????? 第? 4 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 5-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

的設計和開發體驗了很多的設計模式,比如Factoty模式、Singleton模式、Strategy模式、

State模式等等(我有一篇Blog中有關于這個的不完全的描述);另外一方面是這個設計模

式解析實際上在這些工作的間隙中完成的,我一般會要求自己每天寫一個模式,但是特殊的

時候可能沒有寫或者一天寫了不止一個。寫這些文章,本身沒有任何功利的雜念,只是一個

原生態的沖動,反而很輕松的完成了。有心栽花未必發,無心之事可成功,世間的事情可能

在很多的時候恰恰就是那樣了。?

??? 最后想用自己在閱讀、學習、理解、實現、應用、思考設計模式后的一個感悟結束這個

后記:只有真正理解了設計模式,才知道什么叫面向對象分析和設計。?

??????????????????????????????????? k_eckel 寫畢于2005-05-04 (五四青年節)? 1 :01

0.3?? 與作者聯系

??? Author????? K_Eckel

???? State????? Candidate for Master’s Degree School of Computer Wuhan University

??? E_mail????? frwei@whu.edu.cn

1? 創建型模式

1.1 Factory 模式

?問題

??? 在面向對象系統設計中經常可以遇到以下的兩類問題:

???? 1 )為了提高內聚(Cohesion)和松耦合(Coupling ),我們經常會抽象出一些類的公共

接口以形成抽象基類或者接口。這樣我們可以通過聲明一個指向基類的指針來指向實際的子

類實現,達到了多態的目的。這里很容易出現的一個問題n 多的子類繼承自抽象基類,我們

不得不在每次要用到子類的地方就編寫諸如 new?????????????????? ×××;的代碼。這里帶來兩個問題 1)客

戶程序員必須知道實際子類的名稱 (當系統復雜后,命名將是一個很不好處理的問題,為了

處理可能的名字沖突,有的命名可能并不是具有很好的可讀性和可記憶性,就姑且不論不同

程序員千奇百怪的個人偏好了。),2)程序的擴展性和維護變得越來越困難。

????????????????????????????? 第? 5 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 6-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???? 2 )還有一種情況就是在父類中并不知道具體要實例化哪一個具體的子類。這里的意思

為:假設我們在類A? 中要使用到類B,B 是一個抽象父類,在 A? 中并不知道具體要實例化

那一個B 的子類,但是在類A 的子類D 中是可以知道的。在A 中我們沒有辦法直接使用類

似于new??? ×××的語句,因為根本就不知道×××是什么。

??? 以上兩個問題也就引出了Factory 模式的兩個最重要的功能:

???? 1 )定義創建對象的接口,封裝了對象的創建;

???? 2 )使得具體化類的工作延遲到了子類中。

?模式選擇

??? 我們通常使用Factory 模式來解決上面給出的兩個問題。在第一個問題中,我們經常就

是聲明一個創建對象的接口,并封裝了對象的創建過程。Factory??????????????????????? 這里類似于一個真正意義

上的工廠(生產對象)。在第二個問題中,我們需要提供一個對象創建對象的接口,并在子

類中提供其具體實現(因為只有在子類中可以決定到底實例化哪一個類)。

??? 第一中情況的Factory 的結構示意圖為:

????????????????????????? 圖1:Factory 模式結構示意圖 1

??? 圖 1 所以的Factory 模式經常在系統開發中用到,但是這并不是 Factory 模式的最大威

力所在 (因為這可以通過其他方式解決這個問題)。Factory 模式不單是提供了創建對象的接

口,其最重要的是延遲了子類的實例化(第二個問題),以下是這種情況的一個 Factory???????????????????????????????? 的

結構示意圖:

?????????????????????????????? 第? 6 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 7-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????????????? 圖2:Factory 模式結構示意圖 1

??? 圖2 中關鍵中Factory 模式的應用并不是只是為了封裝對象的創建,而是要把對象的創

建放到子類中實現:Factory???????? 中只是提供了對象創建的接口,其實現將放在 Factory?????????????????? 的子類

ConcreteFactory 中進行。這是圖2 和圖 1 的區別所在。

?實現

?完整代碼示例(code)

???? Factory 模式的實現比較簡單,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

?????????????????????????????? 第? 7 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 8-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 1:Product.h??????????????????????????????????????????????? 代碼片斷2:Product.cpp

? //Product.h????????????????????????????????????????????????????? //Product.cpp

? #ifndef _PRODUCT_H_????????????????????????????????????????????? #include "Product.h"

? #define _PRODUCT_H_

?????????????????????????????????????????????????????????????????? #include <iostream>

? class Product??????????????????????????????????????????????????? using namespace std;

?? {

? public:????????????????????????????????????????????????????????? Product::Product()

???????? virtual ~Product() = 0;?????????????????????????????????? {

? protected:?????????????????????????????????????????????????????? }

????????? Product();

?????????????????????????????????????????????????????????????????? Product::~Product()

? private:???????????????????????????????????????????????????????? {

? };?????????????????????????????????????????????????????????????? }

? class ConcreteProduct:public Product???????????????????????????? ConcreteProduct::ConcreteProduct()

?? {?????????????????????????????????????????????????????????????? {

? public:???????????????????????????????????????????????????????????????? cout<<"ConcreteProduct...."<<endl;

????????? ~ConcreteProduct();????????????????????????????????????? }

????????? ConcreteProduct();?????????????????????????????????????? ConcreteProduct::~ConcreteProduct()

?????????????????????????????????????????????????????????????????? {

? protected:

?????????????????????????????????????????????????????????????????? }

? private:

? };

? #endif //~_PRODUCT_H_

???????????????????????????????????????????????? 第? 8?? 頁 共? 105???? 頁??????????????????????????????????????????? k_eckel

----------------------- Page 9-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????? 代碼片斷 3:Factory.h???????????????????????????????????????????? 代碼片斷4:? Factory.cpp

???? //Factory.h??????????????????????????????????????????????????? //Factory.cpp

???? #ifndef _FACTORY_H_??????????????????????????????????????????? #include "Factory.h"

???? #define _FACTORY_H_??????????????????????????????????????????? #include "Product.h"

???? class Product;???????????????????????????????????????????????? #include <iostream>

??????????????????????????????????????????????????????????????????? using namespace std;

???? class Factory

???? {????????????????????????????????????????????????????????????? Factory::Factory()

???? public:??????????????????????????????????????????????????????? {

?????????? virtual ~Factory() = 0;

??????????????????????????????????????????????????????????????????? }

?????????? virtual Product* CreateProduct() = 0;

??????????????????????????????????????????????????????????????????? Factory::~Factory()

???? protected:???????????????????????????????????????????????????? {

??????????? Factory();

??????????????????????????????????????????????????????????????????? }

???? private:

??????????????????????????????????????????????????????????????????? ConcreteFactory::ConcreteFactory()

???? };???????????????????????????????????????????????????????????? {

?????????????????????????????????????????????????????????????????????????? cout<<"ConcreteFactory....."<<endl;

???? class ConcreteFactory:public Factory?????????????????????????? }

???? {

???? public:??????????????????????????????????????????????????????? ConcreteFactory::~ConcreteFactory()

??????????????????????????????????????????????????????????????????? {

??????????? ~ConcreteFactory();

??????????????????????????????????????????????????????????????????? }

??????????? ConcreteFactory();

??????????????????????????????????????????????????????????????????? Product* ConcreteFactory::CreateProduct()

??????????? Product* CreateProduct();?????????????????????????????? {

????????????????????????????????????????????????????????????????????????? return new ConcreteProduct();

???? protected:???????????????????????????????????????????????????? }

???? private:

???? };

???? #endif //~_FACTORY_H_

???????????????????????????????????????????????? 第? 9?? 頁 共? 105????? 頁??????????????????????????????????????????? k_eckel

----------------------- Page 10-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????? 代碼片斷 5:main.cpp

? //main.cpp

? #include "Factory.h"

? #include "Product.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

????? Factory* fac = new ConcreteFactory();

????? Product* p = fac->CreateProduct();

?????? return 0;

? }

?代碼說明

??? 示例代碼中給出的是Factory 模式解決父類中并不知道具體要實例化哪一個具體的子類

的問題,至于為創建對象提供接口問題,可以由 Factory??????????????????????????? 中附加相應的創建操作例如

Create***Product ()即可。具體請參加討論內容。

?討論

???? Factory 模式在實際開發中應用非常廣泛,面向對象的系統經常面臨著對象創建問題:

要創建的類實在是太多了。而 Factory??????????????? 提供的創建對象的接口封裝(第一個功能),以及其

將類的實例化推遲到子類 (第二個功能)都部分地解決了實際問題。一個簡單的例子就是筆

者開開發VisualCMCS 系統的語義分析過程中,由于要為文法中的每個非終結符構造一個類

處理,因此這個過程中對象的創建非常多,采用Factory 模式后系統可讀性性和維護都變得

elegant 許多。

??? Factory 模式也帶來至少以下兩個問題:

??? 1)如果為每一個具體的ConcreteProduct 類的實例化提供一個函數體,那么我們可能不

得不在系統中添加了一個方法來處理這個新建的 ConcreteProduct,這樣Factory 的接口永遠

就不肯能封閉 (Close)。當然我們可以通過創建一個Factory 的子類來通過多態實現這一點,

但是這也是以新建一個類作為代價的。

??? 2 )在實現中我們可以通過參數化工廠方法,即給 FactoryMethod?????????????????????? ()傳遞一個參數用以

???????????????????????????????? 第? 10 頁 共? 105 頁???????????????????????????? k_eckel

----------------------- Page 11-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

決定是創建具體哪一個具體的Product? (實際上筆者在VisualCMCS 中也正是這樣做的)。當

然也可以通過模板化避免 1)中的子類創建子類,其方法就是將具體 Product 類作為模板參

數,實現起來也很簡單。

??? 可以看出,Factory???? 模式對于對象的創建給予開發人員提供了很好的實現策略,但是

Factory 模式僅僅局限于一類類(就是說 Product 是一類,有一個共同的基類),如果我們要

為不同類的類提供一個對象創建的接口,那就要用AbstractFactory 了。

1.2 AbstactFactory 模式

?問題

??? 假設我們要開發一款游戲,當然為了吸引更多的人玩,游戲難度不能太大 (讓大家都沒

有信心了,估計游戲也就沒有前途了),但是也不能太簡單 (沒有挑戰性也不符合玩家的心

理)。于是我們就可以采用這樣一種處理策略:為游戲設立等級,初級、中級、高級甚至有

BT 級。假設也是過關的游戲,每個關卡都有一些怪物 (monster)守著,玩家要把這些怪物

干掉才可以過關。作為開發者,我們就不得不創建怪物的類,然后初級怪物、中級怪物等都

繼承自怪物類(當然不同種類的則需要另創建類,但是模式相同)。在每個關卡,我們都要

創建怪物的實例,例如初級就創建初級怪物(有很多種類)、中級創建中級怪物等。可以想

象在這個系統中,將會有成千上萬的怪物實例要創建,問題是還要保證創建的時候不會出錯:

初級不能創建 BT? 級的怪物(玩家就郁悶了,玩家一郁悶,游戲也就掛掛了),反之也不可

以。

???? AbstractFactory 模式就是用來解決這類問題的:要創建一組相關或者相互依賴的對象。

?模式選擇

???? AbstractFactory 模式典型的結構圖為:

????????????????????????????? 第? 11 頁 共? 105 頁??????????????????????? k_eckel

----------------------- Page 12-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????????????? 圖2-1:AbstractFactory Pattern 結構圖

???? AbstractFactory 模式關鍵就是將這一組對象的創建封裝到一個用于創建對象的類

?(ConcreteFactory)中,維護這樣一個創建類總比維護n 多相關對象的創建過程要簡單的多。

?實現

?完整代碼示例(code)

???? AbstractFactory 模式的實現比較簡單,這里為了方便初學者的學習和參考,將給出完整

的實現代碼(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 12 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 13-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 1:Product.h???????????????????????????????????????????? 代碼片斷2:Product.cpp

? //Product.h??????????????????????????????????????????????????? //Product.cpp

? #ifndef _PRODUCT_H_??????????????????????????????????????????? #include "Product.h"

? #define _PRODUCT_H_??????????????????????????????????????????? #include <iostream>

? class AbstractProductA???????????????????????????????????????? using namespace std;

? {????????????????????????????????????????????????????????????? AbstractProductA::AbstractProductA()

? public:??????????????????????????????????????????????????????? {????? }

???????? virtual ~AbstractProductA();??????????????????????????? AbstractProductA::~AbstractProductA()

? protected:???????????????????????????????????????????????????? {????? }

???????? AbstractProductA();???????????????????????????????????? AbstractProductB::AbstractProductB()

? private:?????????????????????????????????????????????????????? {

? };???????????????????????????????????????????????????????????? }

? class AbstractProductB???????????????????????????????????????? AbstractProductB::~AbstractProductB()

? {????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????? }

???????? virtual ~AbstractProductB();??????????????????????????? ProductA1::ProductA1()

? protected:???????????????????????????????????????????????????? {

??????? AbstractProductB();???????? private:??????????????????????????? cout<<"ProductA1..."<<endl;

? };???????????????????????????????????????????????????????????? }

? class ProductA1:public AbstractProductA??????????????????????? ProductA1::~ProductA1()

? {????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????? }

???????? ProductA1();??????????????????????????????????????????? ProductA2::ProductA2()

???????? ~ProductA1();?????????????????????????????????????????? {

? protected:????????????? private:????????????????????????????????????? cout<<"ProductA2..."<<endl;

? };???????????????????????????????????????????????????????????? }

? class ProductA2:public AbstractProductA??????????????????????? ProductA2::~ProductA2()

? {????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????? }

???????? ProductA2();??????????????????????????????????????????? ProductB1::ProductB1()

???????? ~ProductA2();?????????????????????????????????????????? {

? protected:??????????? private:??????????????????????????????????????? cout<<"ProductB1..."<<endl;

? };???????????????????????????????????????????????????????????? }

? class ProductB1:public AbstractProductB??????????????????????? ProductB1::~ProductB1()

? {????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????? }

???????? ProductB1();??????????????????????????????????????????? ProductB2::ProductB2()

???????? ~ProductB1();?????????????????????????????????????????? {

? protected:??????????????????????????????????????????????????????????? cout<<"ProductB2..."<<endl;

? private:?????????????????????????????????????????????????????? }

? };???????????????????????????????????????????????????????????? ProductB2::~ProductB2()

? class ProductB2:public AbstractProductB??????????????????????? {

? {????????????????????????????????????????????????????????????? }

? public:

???????? ProductB2();

???????? ~ProductB2();???????????????????????? 第? 13?? 頁 共? 105???? 頁????????????????????????????????????????? k_eckel

? protected:??????????? private:

? };

? #endif //~_PRODUCT_H_ECT_H_

----------------------- Page 14-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????? 代碼片斷 3:AbstractFactory.h???????????????????????????????? 代碼片斷4:AbstractFactory.cpp

???? //AbstractFactory.h?????????????????????????????????????? //AbstractFactory.cpp

???? #ifndef _ABSTRACTFACTORY_H_?????????????????????????????? #include "AbstractFactory.h"

???? #define _ABSTRACTFACTORY_H_?????????????????????????????? #include "Product.h"

???? class AbstractProductA;?????????????????????????????????? #include <iostream>

???? class AbstractProductB;?????????????????????????????????? using namespace std;

???? class AbstractFactory???????????????????????????????????? AbstractFactory::AbstractFactory()

???? {????????????????????????????????????????????????????????? {

???? public:

??????????? virtual ~AbstractFactory();??????????????????????? }

??????????? virtual?????????????? AbstractProductA*??????????? AbstractFactory::~AbstractFactory()

???? CreateProductA() = 0;????????????????????????????????????? {

??????????? virtual?????????????? AbstractProductB*??????????? }

???? CreateProductB() = 0;???????????????????????????????????? ConcreteFactory1::ConcreteFactory1()

???? protected:???????????????????????????????????????????????? {

??????????? AbstractFactory();???????????????????????????????? }

???? private:????????????????????????????????????????????????? ConcreteFactory1::~ConcreteFactory1()

???? };???????????????????????????????????????????????????????? {

???? class ConcreteFactory1:public AbstractFactory???????????? }

???? {???????????????????????????????????????????????????????? AbstractProductA*

???? public:?????????????????????????????????????????????????? ConcreteFactory1::CreateProductA()

??????????? ConcreteFactory1();???????????????????????????????? {

??????????? ~ConcreteFactory1();???????????????????????????????????? return new ProductA1();

??????????? AbstractProductA* CreateProductA();??????????????? }

??????????? AbstractProductB* CreateProductB();??????????????? AbstractProductB*

???? protected:??????????????????????????????????????????????? ConcreteFactory1::CreateProductB()

???? private:?????????????????????????????????????????????????? {

???? };????????????????????????????????????????????????????????????? return new ProductB1();

???? class ConcreteFactory2:public AbstractFactory???????????? }

???? {???????????????????????????????????????????????????????? ConcreteFactory2::ConcreteFactory2()

???? public:??????????????????????????????????????????????????? {

??????????? ConcreteFactory2();??????????????????????????????? }

??????????? ~ConcreteFactory2();?????????????????????????????? ConcreteFactory2::~ConcreteFactory2()

??????????? AbstractProductA* CreateProductA();???????????????? {

??????????? AbstractProductB* CreateProductB();??????????????? }

???? protected:??????????????????????????????????????????????? AbstractProductA*

???? private:????????????????????????????????????????????????? ConcreteFactory2::CreateProductA()

???? };???????????????????????????????????????????????????????? {

???? #endif //~_ABSTRACTFACTORY_H_?????????????????????????????????? return new ProductA2();

?????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????????????????????? AbstractProductB*

?????????????????????????????????????????????????????????????? ConcreteFactory2::CreateProductB()

??????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????? return new ProductB2();

?????????????????????????????????????????????????????????????? }
????????????????????????????????????????????? 第? 14? 頁 共? 105???? 頁???????????????????????????????????????? k_eckel

----------------------- Page 15-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????? 代碼片斷 5:main.cpp

? //main.cpp

? #include "AbstractFactory.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

?????? AbstractFactory*???? cf1??? =????? new

? ConcreteFactory1();

??????? cf1->CreateProductA();

??????? cf1->CreateProductB();

?????? AbstractFactory*???? cf2??? =????? new

? ConcreteFactory2();

??????? cf2->CreateProductA();

??????? cf2->CreateProductB();

??????? return 0;

? }

?代碼說明

????? AbstractFactory 模式的實現代碼很簡單,在測試程序中可以看到,當我們要創建一組對

象(ProductA1,ProductA2 )的時候我們只用維護一個創建對象(ConcreteFactory1),大大

簡化了維護的成本和工作。

?討論

????? AbstractFactory 模式和 Factory 模式的區別是初學(使用)設計模式時候的一個容易引

起困惑的地方。實際上,AbstractFactory 模式是為創建一組 (有多類)相關或依賴的對象提

供創建接口,而Factory 模式正如我在相應的文檔中分析的是為一類對象提供創建接口或延

遲對象的創建到子類中實現。并且可以看到,AbstractFactory 模式通常都是使用 Factory 模

式實現(ConcreteFactory1 )。

?????????????????????????????????????? 第? 15? 頁 共? 105?? 頁?????????????????????????????????? k_eckel

----------------------- Page 16-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

1.3 Singleton 模式

?問題

??? 個人認為 Singleton? 模式是設計模式中最為簡單、最為常見、最容易實現,也是最應該

熟悉和掌握的模式。且不說公司企業在招聘的時候為了考察員工對設計的了解和把握,考的

最多的就是 Singleton 模式。

???? Singleton 模式解決問題十分常見,我們怎樣去創建一個唯一的變量(對象)?在基于

對象的設計中我們可以通過創建一個全局變量 (對象)來實現,在面向對象和面向過程結合

的設計范式 (如C++中)中,我們也還是可以通過一個全局變量實現這一點。但是當我們遇

到了純粹的面向對象范式中,這一點可能就只能是通過 Singleton? 模式來實現了,可能這也

正是很多公司在招聘Java 開發人員時候經常考察 Singleton 模式的緣故吧。

???? Singleton 模式在開發中非常有用,具體使用在討論給出。

?模式選擇

???? Singleton 模式典型的結構圖為:

????????????????????????? 圖2-1:Singleton Pattern 結構圖

??? 在 Singleton 模式的結構圖中可以看到,我們通過維護一個static 的成員變量來記錄這

?個唯一的對象實例。通過提供一個 staitc 的接口instance 來獲得這個唯一的實例。

?實現

?完整代碼示例(code)

???? Singleton 模式的實很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代

碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 16 頁 共? 105 頁????????????????????????? k_eckel

----------------------- Page 17-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 1:Singleton.h??????????????????????????????????????????????????? 代碼片斷2:Singleton.cpp

? //Singleton.h?????????????????????????????????????????????????????????? //Singleton.cpp

? #ifndef _SINGLETON_H_?????????????????????????????????????????????????? #include "Singleton.h"

? #define _SINGLETON_H_

????????????????????????????????????????????????????????????????????????? #include <iostream>

? #include <iostream>???????????????????????????????????????????????????? using namespace std;

? using namespace std;

????????????????????????????????????????????????????????????????????????? Singleton* Singleton::_instance = 0;

? class Singleton

?? {????????????????????????????????????????????????????????????????????? Singleton::Singleton()

? public:???????????????????????????????????????????????????????????????? {

???????? static Singleton* Instance();?????????????????????????????????????????? cout<<"Singleton...."<<endl;

????????????????????????????????????????????????????????????????????????? }

? protected:

????????? Singleton();??????????????????????????????????????????????????? Singleton* Singleton::Instance()

????????????????????????????????????????????????????????????????????????? {

? private:????????????????????????????????????????????????????????????????????? if (_instance == 0)

???????? static Singleton* _instance;??????????????????????????????????????????? {

????????????????????????????????????????????????????????????????????????????????????? _instance = new Singleton();

? };???????????????????????????????????????????????????????????????????????????? }

? #endif //~_SINGLETON_H_??????????????????????????????????????????????????????? return _instance;

????????????????????????????????????????????????????????????????????????? }

??????????????? 代碼片斷 3:main.cpp

? //main.cpp

? #include "Singleton.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

?? {

???????? Singleton* sgn = Singleton::Instance();

????????? return 0;

? }

???????????????????????????????????????????????? 第? 17?? 頁 共? 105????? 頁??????????????????????????????????????????? k_eckel

----------------------- Page 18-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

?代碼說明

???? Singleton? 模式的實現無須補充解釋,需要說明的是,Singleton? 不可以被實例化,因此

我們將其構造函數聲明為protected 或者直接聲明為private。

?討論

???? Singleton 模式在開發中經常用到,且不說我們開發過程中一些變量必須是唯一的,比

如說打印機的實例等等。

???? Singleton 模式經常和Factory? (AbstractFactory)模式在一起使用,因為系統中工廠對象

一般來說只要一個,筆者在開發 Visual?? CMCS? 的時候,語義分析過程(以及其他過程)中

都用到工廠模式來創建對象(對象實在是太多了),這里的工廠對象實現就是同時是一個

Singleton 模式的實例,因為系統我們就只要一個工廠來創建對象就可以了。

1.4 Builder 模式

?問題

??? 生活中有著很多的Builder 的例子,個人覺得大學生活就是一個Builder 模式的最好體驗:

要完成大學教育,一般將大學教育過程分成4 個學期進行,因此沒有學習可以看作是構建完

整大學教育的一個部分構建過程,每個人經過這4 年的 (4 個階段)構建過程得到的最后的

結果不一樣,因為可能在四個階段的構建中引入了很多的參數(每個人的機會和際遇不完全

相同)。

???? Builder 模式要解決的也正是這樣的問題:當我們要創建的對象很復雜的時候(通常是

由很多其他的對象組合而成),我們要要復雜對象的創建過程和這個對象的表示(展示)分

離開來,這樣做的好處就是通過一步步的進行復雜對象的構建,由于在每一步的構造過程中

可以引入參數,使得經過相同的步驟創建最后得到的對象的展示不一樣。

?模式選擇

??? Builder 模式的典型結構圖為:

????????????????????????????? 第? 18 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 19-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????????????? 圖2-1:Builder Pattern 結構圖

???? Builder 模式的關鍵是其中的Director 對象并不直接返回對象,而是通過一步步

?(BuildPartA,BuildPartB,BuildPartC)來一步步進行對象的創建。當然這里Director 可以

提供一個默認的返回對象的接口 (即返回通用的復雜對象的創建,即不指定或者特定唯一指

定BuildPart 中的參數)。

?實現

?完整代碼示例(code)

???? Builder 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代

碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 19 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 20-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????? 代碼片斷 1:Product.h??????????????????????????????????????????? 代碼片斷2:Product.cpp

???? //Product.h????????????????????????????????????????????????? //Component.cpp

???? #ifndef _PRODUCT_H_????????????????????????????????????????? #include "Component.h"

???? #define _PRODUCT_H_

?????????????????????????????????????????????????????????????????? Component::Component()

???? class Product???????????????????????????????????????????????? {

???? {

???? public:?????????????????????????????????????????????????????? }

??????????? Product();

?????????????????????????????????????????????????????????????????? Component::~Component()

??????????? ~Product();??????????????????????????????????????????? {

??????????? void ProducePart();??????????????????????????????????? }

???? protected:?????????????????????????????????????????????????? void????? Component::Add(const???????? Component&

?????????????????????????????????????????????????????????????????? com)

???? private:????????????????????????????????????????????????????? {

???? };??????????????????????????????????????????????????????????? }

???? class ProductPart???????????????????????????????????????????? Component* Component::GetChild(int index)

???? {???????????????????????????????????????????????????????????? {

???? public:????????????????????????????????????????????????????????????? return 0;

??????????? ProductPart();???????????????????????????????????????? }

??????????? ~ProductPart();?????????????????????????????????????? void??? Component::Remove(const??????? Component&

?????????????????????????????????????????????????????????????????? com)

??????????? ProductPart* BuildPart();????????????????????????????? {

???? protected:??????????????????????????????????????????????????? }

???? private:

???? };

???? #endif //~_PRODUCT_H_

??????????????????????????????????????????????? 第? 20?? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 21-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????? 代碼片斷 3:Builder.h??????????????????????????????????????????? 代碼片斷4:Builder.cpp

???? //Builder.h????????????????????????????????????????????????? //Builder.cpp

???? #ifndef _BUILDER_H_????????????????????????????????????????? #include "Builder.h"

???? #define _BUILDER_H_????????????????????????????????????????? #include "Product.h"

???? #include <string>??????????????????????????????????????????? #include <iostream>

???? using namespace std;???????????????????????????????????????? using namespace std;

???? class Product;?????????????????????????????????????????????? Builder::Builder()

???? class Builder??????????????????????????????????????????????? {

???? {??????????????????????????????????????????????????????????? }

???? public:????????????????????????????????????????????????????? Builder::~Builder()

??????????? virtual ~Builder();?????????????????????????????????? {

?????????? virtual?? void?? BuildPartA(const???? string&????????? }

???? buildPara) = 0;????????????????????????????????????????????? ConcreteBuilder::ConcreteBuilder()

?????????? virtual?? void?? BuildPartB(const???? string&????????? {

???? buildPara) = 0;????????????????????????????????????????????? }

?????????? virtual?? void?? BuildPartC(const???? string&????????? ConcreteBuilder::~ConcreteBuilder()

???? buildPara) = 0;????????????????????????????????????????????? {

?????????? virtual Product* GetProduct() = 0;???????????????????? }

???? protected:?????????????????????????????????????????????????? void?????????? ConcreteBuilder::BuildPartA(const

??????????? Builder();??????????????????????????????????????????? string& buildPara)

???? private:???????????????????????????????????????????????????? {

???? };????????????????????????????????????????????????????????????????? cout<<"Step1:Build

???? class ConcreteBuilder:public Builder???????????????????????? PartA..."<<buildPara<<endl;

???? {??????????????????????????????????????????????????????????? }

???? public:????????????????????????????????????????????????????? void?????????? ConcreteBuilder::BuildPartB(const

??????????? ConcreteBuilder();??????????????????????????????????? string& buildPara)

??????????? ~ConcreteBuilder();?????????????????????????????????? {

?????????? void???????? BuildPartA(const???????? string&???????????????? cout<<"Step1:Build

???? buildPara);????????????????????????????????????????????????? PartB..."<<buildPara<<endl;

?????????? void BuildPartB(const string& buildPara);????????????? }

?????????? void BuildPartC(const string& buildPara);????????????? void?????????? ConcreteBuilder::BuildPartC(const

??????????? Product* GetProduct();??????????????????????????????? string& buildPara)

???? protected:?????????????????????????????????????????????????? {

???? private:??????????????????????????????????????????????????????????? cout<<"Step1:Build

???? };?????????????????????????????????????????????????????????? PartC..."<<buildPara<<endl;

????????????????????????????????????????????????????????????????? }

???? #endif //~_BUILDER_H_??????????????????????????????????????? Product* ConcreteBuilder::GetProduct()

????????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????????? BuildPartA("pre-defined");

???????????????????????????????????????????????????????????????????????? BuildPartB("pre-defined");

???????????????????????????????????????????????????????????????????????? BuildPartC("pre-defined");

??????????????????????????????????????????????????????????????????????? return new Product();

????????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????? 第? 21??? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 22-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????? 代碼片斷 5:Director.h????????????????????????????????????????????????????? 代碼片斷 6:Director.cpp

? //Director.h???????????????????????????????????????????????????????????? //Director.cpp

? #ifndef _DIRECTOR_H_

? #define _DIRECTOR_H_???????????????????????????????????????????????????? #include "director.h"

? class Builder;?????????????????????????????????????????????????????????? #include "Builder.h"

? class Director

?? {?????????????????????????????????????????????????????????????????????? Director::Director(Builder* bld)

? public:????????????????????????????????????????????????????????????????? {

????????? Director(Builder* bld);??????????????????????????????????????????????? _bld = bld;

????????? ~Director();

????????? void Construct();??????????????????????????????????????????????? }

? protected:

? private:???????????????????????????????????????????????????????????????? Director::~Director()

????????? Builder* _bld;?????????????????????????????????????????????????? {

? };?????????????????????????????????????????????????????????????????????? }

? #endif //~_DIRECTOR_H_?????????????????????????????????????????????????? void Director::Construct()

?????????????????????????????????????????????????????????????????????????? {

????????????????????????????????????????????????????????????????????????????????? _bld->BuildPartA("user-defined");

??????????????? 代碼片斷7:main.cpp??????????????????????????????????????????????????? _bld->BuildPartB("user-defined");

? //main.cpp????????????????????????????????????????????????????????????????????? _bld->BuildPartC("user-defined");

? #include "Builder.h"???????????????????????????????????????????????????? }

? #include "Product.h"

? #include "Director.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

?? {

???????? Director*????? d??? =??? new???? Director(new

? ConcreteBuilder());

????????? d->Construct();

????????? return 0;

? }

????????????????????????????????????????????????? 第? 22?? 頁 共? 105????? 頁???????????????????????????????????????????? k_eckel

----------------------- Page 23-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

?代碼說明

???? Builder 模式的示例代碼中,BuildPart? 的參數是通過客戶程序員傳入的,這里為了簡單

說明問題,使用“user-defined”代替,實際的可能是在Construct 方法中傳入這 3 個參數,

這樣就可以得到不同的細微差別的復雜對象了。

?討論

???? GoF 在《設計模式》一書中給出的關于Builder 模式的意圖是非常容易理解、間接的:

將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示 (在示例

代碼中可以通過傳入不同的參數實現這一點)。

??? Builder 模式和 AbstractFactory 模式在功能上很相似,因為都是用來創建大的復雜的對

象,它們的區別是:Builder??????? 模式強調的是一步步創建對象,并通過相同的創建過程可以獲

得不同的結果對象,一般來說 Builder 模式中對象不是直接返回的。而在AbstractFactory 模

式中對象是直接返回的,AbstractFactory 模式強調的是為創建多個相互依賴的對象提供一個

同一的接口。

1.5 Prototype 模式

?問題

??? 關于這個模式,突然想到了小時候看的《西游記》,齊天大圣孫悟空再發飆的時候可以

通過自己頭上的 3 根毛立馬復制出來成千上萬的孫悟空,對付小妖怪很管用 (數量最重要)。

Prototype 模式也正是提供了自我復制的功能,就是說新對象的創建可以通過已有對象進行

創建。在 C++中拷貝構造函數(Copy?? Constructor )曾經是很對程序員的噩夢,淺層拷貝和

深層拷貝的魔魘也是很多程序員在面試時候的快餐和系統崩潰時候的根源之一。

?模式選擇

???? Prototype 模式典型的結構圖為:

????????????????????????????? 第? 23 頁 共? 105 頁??????????????????????? k_eckel

----------------------- Page 24-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????????????????? 圖2-1:Prototype Pattern 結構圖

??? Prototype? 模式提供了一個通過已存在對象進行新對象創建的接口(Clone),Clone????????????????????? ()

實現和具體的實現語言相關,在C++中我們將通過拷貝構造函數實現之。

?實現

?完整代碼示例(code)

???? Prototype 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 24 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 25-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 1:Prototype.h???????????????????????????????????????????? 代碼片斷2:Prototype.cpp

? //Prototype.h?????????????????????????????????????????????????? //Prototype.cpp

????????????????????????????????????????????????????????????????? #include "Prototype.h"

? #ifndef _PROTOTYPE_H_?????????????????????????????????????????? #include <iostream>

? #define _PROTOTYPE_H_?????????????????????????????????????????? using namespace std;

????????????????????????????????????????????????????????????????? Prototype::Prototype()

? class Prototype???????????????????????????????????????????????? {

? {?????????????????????????????????????????????????????????????? }

? public:???????????????????????????????????????????????????????? Prototype::~Prototype()

???????? virtual ~Prototype();??????????????????????????????????? {

????????????????????????????????????????????????????????????????? }

??????? virtual Prototype* Clone() const = 0;???????????????????? Prototype* Prototype::Clone() const

????????????????????????????????????????????????????????????????? {

? protected:???????????????????????????????????????????????????????????? return 0;

???????? Prototype();???????????????????????????????????????????? }

????????????????????????????????????????????????????????????????? ConcretePrototype::ConcretePrototype()

? private:??????????????????????????????????????????????????????? {

????????????????????????????????????????????????????????????????? }

? };????????????????????????????????????????????????????????????? ConcretePrototype::~ConcretePrototype()

????????????????????????????????????????????????????????????????? {

? class ConcretePrototype:public Prototype??????????????????????? }

? {?????????????????????????????????????????????????????????????? ConcretePrototype::ConcretePrototype(const

? public:???????????????????????????????????????????????????????? ConcretePrototype& cp)

???????? ConcretePrototype();???????????????????????????????????? {

???????????????????????????????????????????????????????????????????????? cout<<"ConcretePrototype

???????? ConcretePrototype(const????????????????????????????????? copy ..."<<endl;

? ConcretePrototype& cp);???????????????????????????????????????? }

????????????????????????????????????????????????????????????????? Prototype* ConcretePrototype::Clone() const

???????? ~ConcretePrototype();??????????????????????????????????? {

??????????????????????????????????????????????????????????????????????? return new ConcretePrototype(*this);

??????? Prototype* Clone() const;???????????????????????????????? }

? protected:

? private:

? };

? #endif //~_PROTOTYPE_H_

?????????????????????????????????????????????? 第? 25??? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 26-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????? 代碼片斷 3:main.cpp

?//main.cpp

?#include "Prototype.h"

?#include <iostream>

?using namespace std;

? int main(int argc,char* argv[])

? {

????? Prototype* p = new ConcretePrototype();

????? Prototype* p1 = p->Clone();

?????? return 0;

? }

?代碼說明

??? Prototype 模式的結構和實現都很簡單,其關鍵就是(C++中)拷貝構造函數的實現方

式,這也是C++實現技術層面上的事情。由于在示例代碼中不涉及到深層拷貝(主要指有指

針、復合對象的情況),因此我們通過編譯器提供的默認的拷貝構造函數(按位拷貝)的方

式進行實現。說明的是這一切只是為了實現簡單起見,也因為本文檔的重點不在拷貝構造函

數的實現技術,而在Prototype 模式本身的思想。

?討論

???? Prototype 模式通過復制原型(Prototype)而獲得新對象創建的功能,這里Prototype 本

身就是 “對象工廠”(因為能夠生產對象),實際上 Prototype???????????????????????? 模式和 Builder??? 模式、

AbstractFactory 模式都是通過一個類 (對象實例)來專門負責對象的創建工作 (工廠對象),

它們之間的區別是:Builder?????????? 模式重在復雜對象的一步步創建(并不直接返回對象),

AbstractFactory? 模式重在產生多個相互依賴類的對象,而 Prototype? 模式重在從自身復制自

己創建新類。

2??? 結構型模式

2.1 Bridge 模式

?問題

?????????????????????????????? 第? 26 頁 共? 105 頁?????????????????????????? k_eckel

----------------------- Page 27-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??? 總結面向對象實際上就兩句話:一是松耦合(Coupling ),二是高內聚(Cohesion)。面

向對象系統追求的目標就是盡可能地提高系統模塊內部的內聚(Cohesion)、盡可能降低模

塊間的耦合 (Coupling)。然而這也是面向對象設計過程中最為難把握的部分,大家肯定在

OO 系統的開發過程中遇到這樣的問題:

??? 1)客戶給了你一個需求,于是使用一個類來實現(A );

??? 2 )客戶需求變化,有兩個算法實現功能,于是改變設計,我們通過一個抽象的基類,

再定義兩個具體類實現兩個不同的算法(A1 和A2 );

??? 3)客戶又告訴我們說對于不同的操作系統,于是再抽象一個層次,作為一個抽象基類

A0,在分別為每個操作系統派生具體類(A00 和 A01,其中A00 表示原來的類 A )實現不

同操作系統上的客戶需求,這樣我們就有了一共4 個類。

??? 4 )可能用戶的需求又有變化,比如說又有了一種新的算法……..

??? 5)我們陷入了一個需求變化的郁悶當中,也因此帶來了類的迅速膨脹。

??? Bridge 模式則正是解決了這類問題。

?模式選擇

???? Bridge 模式典型的結構圖為:

?????????????????????????? 圖2-1:Bridge Pattern 結構圖

??? 在Bridge 模式的結構圖中可以看到,系統被分為兩個相對獨立的部分,左邊是抽象部

?分,右邊是實現部分,這兩個部分可以互相獨立地進行修改:例如上面問題中的客戶需求

?變化,當用戶需求需要從Abstraction 派生一個具體子類時候,并不需要像上面通過繼承

?方式實現時候需要添加子類A1 和A2 了。另外當上面問題中由于算法添加也只用改變右

?邊實現(添加一個具體化子類),而右邊不用在變化,也不用添加具體子類了。

???? 一切都變得elegant !

????????????????????????????? 第? 27 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 28-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?實現

?完整代碼示例(code)

?????? Bridge 模式的實現起來并不是特別困難,這里為了方便初學者的學習和參考,將給出完

整的實現代碼(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

???????????? 代碼片斷 1:Abstraction.h??????????????????????????????????????? 代碼片斷2:Abstraction.cpp

? //Abstraction.h????????????????????????????????????????????? //Abstraction.cpp

? #ifndef _ABSTRACTION_H_????????????????????????????????????? #include "Abstraction.h"

? #define _ABSTRACTION_H_????????????????????????????????????? #include "AbstractionImp.h"

? class AbstractionImp;??????????????????????????????????????? #include <iostream>

?????????????????????????????????????????????????????????????? using namespace std;

? class Abstraction

? {??????????????????????????????????????????????????????????? Abstraction::Abstraction()

? public:?????????????????????????????????????????????????????? {

???????? virtual ~Abstraction();

??????????????????????????????????????????????????????????????? }

??????? virtual void Operation() = 0;

?????????????????????????????????????????????????????????????? Abstraction::~Abstraction()

? protected:??????????????????????????????????????????????????? {

???????? Abstraction();

??????????????????????????????????????????????????????????????? }

? private:

?????????????????????????????????????????????????????????????? RefinedAbstraction::RefinedAbstraction(Abstra

? };??????????????????????????????????????????????????????????? ctionImp* imp)

??????????????????????????????????????????????????????????????? {

? class RefinedAbstraction:public Abstraction??????????????????????? _imp = imp;

? {???????????????????????????????????????????????????????????? }

? public:

???????? RefinedAbstraction(AbstractionImp*??????????????????? RefinedAbstraction::~RefinedAbstraction()

? imp);???????????????????????????????????????????????????????? {

???????? ~RefinedAbstraction();???????????????????????????????? }

???????? void Operation();???????????????????????????????????? void RefinedAbstraction::Operation()

??????????????????????????????????????????????????????????????? {

? protected:????????????????????????????????????????????????????????? _imp->Operation();

??????????????????????????????????????????????????????????????? }

? private:

???????? AbstractionImp* _imp;

? };

????????????????????????????????????????????? 第? 28? 頁 共? 105???? 頁???????????????????????????????????????? k_eckel
? #endif //~_ABSTRACTION_H_

----------------------- Page 29-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 3:AbstractionImp.h???????????????????????????????????? 代碼片斷4:AbstractionImp.cpp

???? //AbstractionImp.h??????????????????????????????????????????? //AbstractionImp.cpp

???? #ifndef _ABSTRACTIONIMP_H_??????????????????????????????????? #include "AbstractionImp.h"

???? #define _ABSTRACTIONIMP_H_??????????????????????????????????? #include <iostream>

????? class AbstractionImp???????????????????????????????????????? using namespace std;

????? {??????????????????????????????????????????????????????????? AbstractionImp::AbstractionImp()

???? public:?????????????????????????????????????????????????????? {

??????????? virtual ~AbstractionImp();???????????????????????????? }

?????????? virtual void Operation() = 0;?????????????????????????? AbstractionImp::~AbstractionImp()

???? protected:??????????????????????????????????????????????????? {

??????????? AbstractionImp();????????????????????????????????????? }

???? private:????????????????????????????????????????????????????? void AbstractionImp::Operation()

????? };?????????????????????????????????????????????????????????? {

????? class?????????? ConcreteAbstractionImpA:public????????????????????? cout<<"AbstractionImp....imp..."<<endl;

???? AbstractionImp??????????????????????????????????????????????? }

????? {??????????????????????????????????????????????????????????? ConcreteAbstractionImpA::ConcreteAbstractio

???? public:?????????????????????????????????????????????????????? nImpA()

??????????? ConcreteAbstractionImpA();???????????????????????????? {

??????????? ~ConcreteAbstractionImpA();??????????????????????????? }

?????????? virtual void Operation();?????????????????????????????? ConcreteAbstractionImpA::~ConcreteAbstracti

???? protected:??????????????????????????????????????????????????? onImpA()

???? private:????????????????????????????????????????????????????? {

????? };?????????????????????????????????????????????????????????? }

????? class?????????? ConcreteAbstractionImpB:public?????????????? void ConcreteAbstractionImpA::Operation()

???? AbstractionImp??????????????????????????????????????????????? {

????? {?????????????????????????????????????????????????????????????????? cout<<"ConcreteAbstractionImpA...."<<e

???? public:?????????????????????????????????????????????????????? ndl;

??????????? ConcreteAbstractionImpB();???????????????????????????? }

??????????? ~ConcreteAbstractionImpB();??????????????????????????? ConcreteAbstractionImpB::ConcreteAbstractio

?????????? virtual void Operation();?????????????????????????????? nImpB()

???? protected:??????????????????????????????????????????????????? {

???? private:????????????????????????????????????????????????????? }

????? };?????????????????????????????????????????????????????????? ConcreteAbstractionImpB::~ConcreteAbstracti

?????????????????????????????????????????????????????????????????? onImpB()

???? #endif //~_ABSTRACTIONIMP_H_????????????????????????????????? {

?????????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????????????????????????? void ConcreteAbstractionImpB::Operation()

?????????????????????????????????????????????????????????????????? {

????????????????????????????????????????????????????????????????????????? cout<<"ConcreteAbstractionImpB...."<<e

?????????????????????????????????????????????????????????????????? ndl;

?????????????????????????????????????????????????????????????????? }

????????????????????????????????????????????? 第? 29? 頁 共? 105???? 頁???????????????????????????????????????? k_eckel

----------------------- Page 30-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????? 代碼片斷 5:main.cpp

? //main.cpp

? #include "Abstraction.h"

? #include "AbstractionImp.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

????? AbstractionImp*??? imp??? =???? new

? ConcreteAbstractionImpA();

????? Abstraction*???? abs???? =????? new

? RefinedAbstraction(imp);

?????? abs->Operation();

?????? return 0;

? }

?代碼說明

???? Bridge 模式將抽象和實現分別獨立實現,在代碼中就是Abstraction 類和AbstractionImp

類。

?討論

????? Bridge 是設計模式中比較復雜和難理解的模式之一,也是OO 開發與設計中經常會用到

的模式之一。使用組合 (委托)的方式將抽象和實現徹底地解耦,這樣的好處是抽象和實現

可以分別獨立地變化,系統的耦合性也得到了很好的降低。

???? GoF 在說明Bridge 模式時,在意圖中指出Bridge 模式“將抽象部分與它的實現部分分

離,使得它們可以獨立地變化”。這句話很簡單,但是也很復雜,連Bruce Eckel 在他的大作

?《Thinking in Patterns》中說“Bridge 模式是 GoF 所講述得最不好 (Poorly-described)的模

式”,個人覺得也正是如此。原因就在于GoF 的那句話中的 “實現”該怎么去理解:“實現”

特別是和 “抽象”放在一起的時候我們 “默認”的理解是 “實現”就是 “抽象”的具體子類

的實現,但是這里 GoF? 所謂的“實現”的含義不是指抽象基類的具體子類對抽象基類中虛

函數 (接口)的實現,是和繼承結合在一起的。而這里的 “實現”的含義指的是怎么去實現

??????????????????????????????????? 第? 30 頁 共? 105? 頁?????????????????????????????? k_eckel

----------------------- Page 31-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

用戶的需求,并且指的是通過組合 (委托)的方式實現的,因此這里的實現不是指的繼承基

類、實現基類接口,而是指的是通過對象組合實現用戶的需求。理解了這一點也就理解了

Bridge 模式,理解了Bridge 模式,你的設計就會更加Elegant 了。

??? 實際上上面使用 Bridge? 模式和使用帶來問題方式的解決方案的根本區別在于是通過繼

承還是通過組合的方式去實現一個功能需求。因此面向對象分析和設計中有一個原則就是:

Favor Composition Over Inheritance。其原因也正在這里。

2.2 Adapter 模式

?問題

???? Adapter 模式解決的問題在生活中經常會遇到:比如我們有一個 Team 為外界提供 S 類

服務,但是我們 Team 里面沒有能夠完成此項人物的member,然后我們得知有A 可以完成

這項服務 (他把這項人物重新取了個名字叫S’,并且他不對外公布他的具體實現)。為了保

證我們對外的服務類別的一致性(提供 S 服務),我們有以下兩種方式解決這個問題:

???? 1 )把B 君直接招安到我們Team 為我們工作,提供 S 服務的時候讓B 君去辦就是了;

???? 2 )B? 君可能在別的地方有工作,并且不準備接受我們的招安,于是我們 Team? 可以想

這樣一種方式解決問題:我們安排 C 君去完成這項任務,并做好工作(Money:))讓A 君

工作的時候可以向B 君請教,因此 C 君就是一個復合體(提供 S 服務,但是是B 君的繼承

弟子)。

??? 實際上在軟件系統設計和開發中,這種問題也會經常遇到:我們為了完成某項工作購買

了一個第三方的庫來加快開發。這就帶來了一個問題:我們在應用程序中已經設計好了接口,

與這個第三方提供的接口不一致,為了使得這些接口不兼容的類 (不能在一起工作)可以在

一起工作了,Adapter 模式提供了將一個類(第三方庫)的接口轉化為客戶(購買使用者)

希望的接口。

??? 在上面生活中問題的解決方式也就正好對應了Adapter 模式的兩種類別:類模式和對象

模式。

?模式選擇

???? Adapter 模式典型的結構圖為:

????????????????????????????? 第? 31 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 32-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????????????? 圖2-1:Adapter Pattern (類模式)結構圖

???????????????????? 圖2-2:Adapter Pattern (對象模式)結構圖

??? 在 Adapter? 模式的結構圖中可以看到,類模式的 Adapter? 采用繼承的方式復用 Adaptee

的接口,而在對象模式的Adapter 中我們則采用組合的方式實現Adaptee 的復用。有關這些

具體的實現和分析將在代碼說明和討論中給出。

?實現

?完整代碼示例(code)

???? Adapter 模式的實很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代碼

?(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

??? 類模式的Adapter 實現:

????????????????????????????? 第? 32 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 33-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 1:Adapter.h???????????????????????????????????????????????????? 代碼片斷2:Adapter.cpp

? //Adapter.h?????????????????????????????????????????????????????????? //Adapter.cpp

? #ifndef _ADAPTER_H_?????????????????????????????????????????????????? #include "Adapter.h"

? #define _ADAPTER_H_?????????????????????????????????????????????????? #include <iostream>

? class Target????????????????????????????????????????????????????????? Target::Target()

?? {??????????????????????????????????????????????????????????????????? {

? public:?????????????????????????????????????????????????????????????? }

???????? Target();????????????????????????????????????????????????????? Target::~Target()

???????? virtual ~Target();???????????????????????????????????????????? {

??????? virtual void Request();???????????????????????????????????????? }

? protected:??????????????????????????????????????????????????????????? void Target::Request()

? private:????????????????????????????????????????????????????????????? {

? };?????????????????????????????????????????????????????????????????????????? std::cout<<"Target::Request"<<std::endl;

? class Adaptee???????????????????????????????????????????????????????? }

?? {??????????????????????????????????????????????????????????????????? Adaptee::Adaptee()

? public:?????????????????????????????????????????????????????????????? {

???????? Adaptee();

???????? ~Adaptee();??????????????????????????????????????????????????? }

???????? void SpecificRequest();

? protected:??????????????????????????????????????????????????????????? Adaptee::~Adaptee()

? private:????????????????????????????????????????????????????????????? {

? };??????????????????????????????????????????????????????????????????? }

? class Adapter:public Target,private Adaptee?????????????????????????? void Adaptee::SpecificRequest()

?? {??????????????????????????????????????????????????????????????????? {

? public:????????????????????????????????????????????????????????????????????? std::cout<<"Adaptee::SpecificRequest"<<

???????? Adapter();???????????????????????????????????????????????????? std::endl;

???????? ~Adapter();??????????????????????????????????????????????????? }

???????? void Request();??????????????????????????????????????????????? Adapter::Adapter()

? protected:??????????????????????????????????????????????????????????? {

? private:????????????????????????????????????????????????????????????? }

? };??????????????????????????????????????????????????????????????????? Adapter::~Adapter()

? #endif //~_ADAPTER_H_???????????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????????????????????????????? void Adapter::Request()

??????????????????????????????????????????????????????????????????????? {

?????????????????????????????????????????????????????????????????????????????? this->SpecificRequest();

??????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????? 第? 33?? 頁 共? 105????? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 34-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 1:Adapter.h???????????????????????????????????????????????????? 代碼片斷2:Adapter.cpp

? //Adapter.h?????????????????????????????????????????????????????????? //Adapter.cpp

? #ifndef _ADAPTER_H_?????????????????????????????????????????????????? #include "Adapter.h"

? #define _ADAPTER_H_?????????????????????????????????????????????????? #include <iostream>

? class Target????????????????????????????????????????????????????????? Target::Target()

?? {??????????????????????????????????????????????????????????????????? {

? public:?????????????????????????????????????????????????????????????? }

???????? Target();????????????????????????????????????????????????????? Target::~Target()

???????? virtual ~Target();???????????????????????????????????????????? {

??????? virtual void Request();???????????????????????????????????????? }

? protected:??????????????????????????????????????????????????????????? void Target::Request()

? private:????????????????????????????????????????????????????????????? {

? };?????????????????????????????????????????????????????????????????????????? std::cout<<"Target::Request"<<std::endl;

? class Adaptee???????????????????????????????????????????????????????? }

?? {??????????????????????????????????????????????????????????????????? Adaptee::Adaptee()

? public:?????????????????????????????????????????????????????????????? {

???????? Adaptee();???????????????????????????????????????????????????? }

???????? ~Adaptee();??????????????????????????????????????????????????? Adaptee::~Adaptee()

???????? void SpecificRequest();??????????????????????????????????????? {

? protected:??????????????????????????????????????????????????????????? }

? private:????????????????????????????????????????????????????????????? void Adaptee::SpecificRequest()

? };??????????????????????????????????????????????????????????????????? {

? class Adapter:public Target????????????????????????????????????????????????? std::cout<<"Adaptee::SpecificRequest"<<

?? {??????????????????????????????????????????????????????????????????? std::endl;

? public:?????????????????????????????????????????????????????????????? }

???????? Adapter(Adaptee* ade);???????????????????????????????????????? Adapter::Adapter(Adaptee* ade)

???????? ~Adapter();??????????????????????????????????????????????????? {

???????? void Request();?????????????????????????????????????????????????????? this->_ade = ade;

? protected:??????????????????????????????????????????????????????????? }

? private:????????????????????????????????????????????????????????????? Adapter::~Adapter()

???????? Adaptee* _ade;???????????????????????????????????????????????? {

? };??????????????????????????????????????????????????????????????????? }

? #endif //~_ADAPTER_H_???????????????????????????????????????????????? void Adapter::Request()

??????????????????????????????????????????????????????????????????????? {

?????????????????????????????????????????????????????????????????????????????? _ade->SpecificRequest();

??????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????? 第? 34?? 頁 共? 105????? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 35-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????? 代碼片斷 3:main.cpp

? //main.cpp

? #include "Adapter.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

????? Adaptee* ade = new Adaptee;

????? Target* adt = new Adapter(ade);

?????? adt->Request();

?????? return 0;

? }

?代碼說明

???? Adapter 模式實現上比較簡單,要說明的是在類模式Adapter? 中,我們通過private 繼承

Adaptee 獲得實現繼承的效果,而通過public 繼承Target 獲得接口繼承的效果 (有關實現繼

承和接口繼承參見討論部分)。

?討論

??? 在Adapter 模式的兩種模式中,有一個很重要的概念就是接口繼承和實現繼承的區別和

聯系。接口繼承和實現繼承是面向對象領域的兩個重要的概念,接口繼承指的是通過繼承,

子類獲得了父類的接口,而實現繼承指的是通過繼承子類獲得了父類的實現 (并不統共接

口)。在C++中的public 繼承既是接口繼承又是實現繼承,因為子類在繼承了父類后既可以

對外提供父類中的接口操作,又可以獲得父類的接口實現。當然我們可以通過一定的方式和

技術模擬單獨的接口繼承和實現繼承,例如我們可以通過 private? 繼承獲得實現繼承的效果

?(private 繼承后,父類中的接口都變為 private,當然只能是實現繼承了。),通過純抽象基

類模擬接口繼承的效果,但是在 C++中pure virtual function 也可以提供默認實現,因此這是

不純正的接口繼承,但是在Java 中我們可以interface 來獲得真正的接口繼承了。

2.3 Decorator 模式

?問題

???????????????????????????????? 第? 35 頁 共? 105 頁???????????????????????????? k_eckel

----------------------- Page 36-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??? 在OO 設計和開發過程,可能會經常遇到以下的情況:我們需要為一個已經定義好的類

添加新的職責(操作),通常的情況我們會給定義一個新類繼承自定義好的類,這樣會帶來

一個問題(將在本模式的討論中給出)。通過繼承的方式解決這樣的情況還帶來了系統的復

雜性,因為繼承的深度會變得很深。

??? 而 Decorator 提供了一種給類增加職責的方法,不是通過繼承實現的,而是通過組合。

有關這些內容在討論中進一步闡述。

?模式選擇

???? Decorator 模式典型的結構圖為:

???????????????????????? 圖2-1:Decorator Pattern 結構圖

??? 在 結 構 圖 中 ,ConcreteComponent???? 和? Decorator 需 要 有 同 樣 的 接 口 , 因 此

ConcreteComponent 和Decorator 有著一個共同的父類。這里有人會問,讓Decorator 直接維

護一個指向ConcreteComponent 引用 (指針)不就可以達到同樣的效果,答案是肯定并且是

否定的。肯定的是你可以通過這種方式實現,否定的是你不要用這種方式實現,因為通過這

種方式你就只能為這個特定的 ConcreteComponent?????????????? 提供修飾操作了,當有了一個新的

ConcreteComponent 你又要去新建一個 Decorator?????????? 來實現。但是通過結構圖中的

ConcreteComponent 和Decorator 有一個公共基類,就可以利用OO 中多態的思想來實現只要

是 Component? 型別的對象都可以提供修飾操作的類,這種情況下你就算新建了 100?????????????????????????????? 個

????????????????????????????? 第? 36 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 37-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

Component 型別的類 ConcreteComponent ,也都可以由 Decorator???????? 一個類搞定。這也正是

Decorator 模式的關鍵和威力所在了。

??? 當然如果你只用給Component 型別類添加一種修飾,則Decorator 這個基類就不是很必

要了。

?實現

?完整代碼示例(code)

???? Decorator 模式的實現起來并不是特別困難,這里為了方便初學者的學習和參考,將給

出完整的實現代碼(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 37 頁 共? 105 頁????????????????????????? k_eckel

----------------------- Page 38-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 1:Decorator.h????????????????????????????????????????? 代碼片斷2:Decorator.cpp

? //Decorator.h???????????????????????????????????????????????? //Decorator.cpp

? #ifndef _DECORATOR_H_???????????????????????????????????????? #include "Decorator.h"

? #define _DECORATOR_H_???????????????????????????????????????? #include <iostream>

? class Component?????????????????????????????????????????????? Component::Component()

? {???????????????????????????????????????????????????????????? {

? public:?????????????????????????????????????????????????????? }

???????? virtual ~Component();????????????????????????????????? Component::~Component()

??????? virtual void?? Operation();???????????????????????????? {??? }

? protected:??????????????????????????????????????????????????? void Component::Operation()

???????? Component();?????????????????????????????????????????? {??? }

? private:????????????????????????????????????????????????????? ConcreteComponent::ConcreteComponent()

? };??????????????????????????????????????????????????????????? {??? }

? class ConcreteComponent:public Component????????????????????? ConcreteComponent::~ConcreteComponent()

? {???????????????????????????????????????????????????????????? {??? }

? public:?????????????????????????????????????????????????????? void ConcreteComponent::Operation()

???????? ConcreteComponent();?????????????????????????????????? {

???????? ~ConcreteComponent();???????????????????????????????????????? std::cout<<"ConcreteComponent

??????? void?? Operation();???????????????????????????????????? operation..."<<std::endl;

? protected:??????????????????????????????????????????????????? }

? private:????????????????????????????????????????????????????? Decorator::Decorator(Component* com)

? };??????????????????????????????????????????????????????????? {

? class Decorator:public Component??????????????????????????????????? this->_com = com;

? {???????????????????????????????????????????????????????????? }

? public:?????????????????????????????????????????????????????? Decorator::~Decorator()

???????? Decorator(Component* com);???????????????????????????? {

???????? virtual ~Decorator();???????????????????????????????????????? delete _com;

??????? void?? Operation();???????????????????????????????????? }

? protected:??????????????????????????????????????????????????? void Decorator::Operation()

???????? Component* _com;?????????????????????????????????????? {?? }

? private:????????????????????????????????????????????????????? ConcreteDecorator::ConcreteDecorator(Compo

? };??????????????????????????????????????????????????????????? nent* com):Decorator(com)

? class ConcreteDecorator:public Decorator????????????????????? {??? }

? {???????????????????????????????????????????????????????????? ConcreteDecorator::~ConcreteDecorator()

? public:?????????????????????????????????????????????????????? {??? }

???????? ConcreteDecorator(Component* com);???????????????????? void ConcreteDecorator::AddedBehavior()

???????? ~ConcreteDecorator();????????????????????????????????? {

??????? void?? Operation();??????????????????????????????????????????? std::cout<<"ConcreteDecorator::AddedBe

???????? void AddedBehavior();????????????????????????????????? hacior...."<<std::endl;

? protected:??????????????????????????????????????????????????? }

? private:????????????????????????????????????????????????????? void ConcreteDecorator::Operation()

? };??????????????????????????????????????????????????????????? {

? #endif //~_DECORATOR_H_????????????????????????????????????????????? _com->Operation();

?????????????????????????????????????????????????????????????????????? this->AddedBehavior();

??????????????????????????????????????????????????????????????? }
????????????????????????????????????????????? 第? 38?? 頁 共? 105???? 頁???????????????????????????????????????? k_eckel

----------------------- Page 39-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????? 代碼片斷 3:main.cpp

? //main.cpp

? #include "Decorator.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

?????? Component*?????? com????? =???? new

? ConcreteComponent();

?????? Decorator*????? dec????? =???? new

? ConcreteDecorator(com);

?????? dec->Operation();

?????? delete dec;

?????? return 0;

? }

?代碼說明

???? Decorator? 模式很簡單,代碼本身沒有什么好說明的。運行示例代碼可以看到,

ConcreteDecorator 給ConcreteComponent 類添加了動作AddedBehavior 。

?討論

????? Decorator 模式和Composite 模式有相似的結構圖,其區別在 Composite 模式已經詳細討

論過了,請參看相應文檔。另外GoF 在 《設計模式》中也討論到Decorator 和Proxy 模式有

很大程度上的相似,初學設計模式可能實在看不出這之間的一個聯系和相似,并且它們在結

構圖上也很不相似。實際上,在本文檔 2.2 節模式選擇中分析到,讓 Decorator 直接擁有一

個ConcreteComponent 的引用 (指針)也可以達到修飾的功能,大家再把這種方式的結構圖

畫出來,就和Proxy 很相似了!

????? Decorator 模式和Proxy 模式的相似的地方在于它們都擁有一個指向其他對象的引用(指

針),即通過組合的方式來為對象提供更多操作(或者Decorator 模式)間接性 (Proxy 模式)。

???????????????????????????????????? 第? 39 頁 共? 105?? 頁???????????????????????????????? k_eckel

----------------------- Page 40-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

但是他們的區別是,Proxy 模式會提供使用其作為代理的對象一樣接口,使用代理類將其操

作都委托給Proxy 直接進行。這里可以簡單理解為組合和委托之間的微妙的區別了。

???? Decorator 模式除了采用組合的方式取得了比采用繼承方式更好的效果,Decorator 模式

還給設計帶來一種“即用即付”的方式來添加職責。在OO 設計和分析經常有這樣一種情況:

為了多態,通過父類指針指向其具體子類,但是這就帶來另外一個問題,當具體子類要添加

新的職責,就必須向其父類添加一個這個職責的抽象接口,否則是通過父類指針是調用不到

這個方法了。這樣處于高層的父類就承載了太多的特征(方法),并且繼承自這個父類的所

有子類都不可避免繼承了父類的這些接口,但是可能這并不是這個具體子類所需要的。而在

Decorator 模式提供了一種較好的解決方法,當需要添加一個操作的時候就可以通過

Decorator 模式來解決,你可以一步步添加新的職責。

2.4 Composite 模式

?問題

??? 在開發中,我們經常可能要遞歸構建樹狀的組合結構,Composite 模式則提供了很好的

解決方案。

?模式選擇

??? Composite 模式的典型結構圖為:

????????????????????????????? 第? 40 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 41-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????????????????????????? 圖2-1:Composite Pattern 結構圖

?實現

?完整代碼示例(code)

????? Composite 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????? 代碼片斷 1:Component.h?????????????????????????????????? 代碼片斷2:Component.cpp

??? //Component.h????????????????????????????????????????? //Component.cpp

??? #ifndef _COMPONENT_H_????????????????????????????????? #include "Component.h"

??? #define _COMPONENT_H_

?????????????????????????????????????????????????????????? Component::Component()

??? class Component??????????????????????????????????????? {

???? {

??? public:??????????????????????????????????????????????? }

?????????? Component();

?????????????????????????????????????????????????????????? Component::~Component()

?????????? virtual ~Component();?????????????????????????? {

??? public:??????????????????????????????????????????????? }

????????? virtual void Operation() = 0;

?????????????????????????????????????????????????????????? void??? Component::Add(const???? Component&

????????? virtual void Add(const Component& );???????????? com)

?????????????????????????????????????????????????????????? {

????????? virtual??????? void??????? Remove(const

??? Component& );????????????????????????????????????????? }

????????? virtual Component* GetChild(int );?????????????? Component* Component::GetChild(int index)

?????????????????????????????????????????????????????????? {

??? protected:?????????????????????????????????????????????????? return 0;

?????????????????????????????????????????????????????????? }

??? private:

?????????????????????????????????????????????????????????? void? Component::Remove(const??? Component&

??? };???????????????????????????????????????????????????? com)

?????????????????????????????????????????????????????????? {

??? #endif //~_COMPONENT_H_

?????????????????????????????????????????????????????????? }

????????????????????????????????????????? 第? 41? 頁 共? 105??? 頁????????????????????????????????????? k_eckel

----------------------- Page 42-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????? 代碼片斷 3:Composite.h???????????????????????????????????????????? 代碼片斷4:Composite.cpp

? //Composite.h???????????????????????????????????????????????????? //Composite.cpp

??????????????????????????????????????????????????????????????????? #include "Composite.h"

? #ifndef _COMPOSITE_H_???????????????????????????????????????????? #include "Component.h"

? #define _COMPOSITE_H_???????????????????????????????????????????? #define NULL 0??????? //define NULL POINTOR

??????????????????????????????????????????????????????????????????? Composite::Composite()

? #include "Component.h"??????????????????????????????????????????? {

? #include <vector>?????????????????????????????????????????????????????? //vector<Component*>::iterator???????? itend?? =

? using namespace std;????????????????????????????????????????????? comVec.begin();

??????????????????????????????????????????????????????????????????? }

? class Composite:public Component????????????????????????????????? Composite::~Composite()

?? {??????????????????????????????????????????????????????????????? {

? public:?????????????????????????????????????????????????????????? }

????????? Composite();????????????????????????????????????????????? void Composite::Operation()

??????????????????????????????????????????????????????????????????? {

????????? ~Composite();??????????????????????????????????????????????????? vector<Component*>::iterator?????? comIter?? =

??????????????????????????????????????????????????????????????????? comVec.begin();

? public:

????????? void Operation();??????????????????????????????????????????????? for (;comIter != comVec.end();comIter++)

?????????????????????????????????????????????????????????????????????????? {

????????? void Add(Component* com);????????????????????????????????????????????? (*comIter)->Operation();

?????????????????????????????????????????????????????????????????????????? }

???????? void Remove(Component* com);?????????????????????????????? }

??????????????????????????????????????????????????????????????????? void Composite::Add(Component* com)

???????? Component* GetChild(int index);??????????????????????????? {

?????????????????????????????????????????????????????????????????????????? comVec.push_back(com);

? protected:??????????????????????????????????????????????????????? }

??????????????????????????????????????????????????????????????????? void Composite::Remove(Component* com)

? private:????????????????????????????????????????????????????????? {

????????? vector<Component*> comVec;?????????????????????????????????????? comVec.erase(&com);

??????????????????????????????????????????????????????????????????? }

? };??????????????????????????????????????????????????????????????? Component* Composite::GetChild(int index)

??????????????????????????????????????????????????????????????????? {

? #endif //~_COMPOSITE_H_????????????????????????????????????????????????? return comVec[index];

??????????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????? 第? 42?? 頁 共? 105????? 頁??????????????????????????????????????????? k_eckel

----------------------- Page 43-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????? 代碼片斷 5:leaf.h?????????????????????????????????????????????????????? 代碼片斷 6:Leaf.cpp

? //Leaf.h????????????????????????????????????????????????????????????? //Leaf.cpp

? #ifndef _LEAF_H_

? #define _LEAF_H_????????????????????????????????????????????????????? #include "Leaf.h"

??????????????????????????????????????????????????????????????????????? #include <iostream>

? #include "Component.h"??????????????????????????????????????????????? using namespace std;

? class Leaf:public Component?????????????????????????????????????????? Leaf::Leaf()

?? {???????????????????????????????????????????????????????????????????? {

? public:

???????? Leaf();???????????????????????????????????????????????????????? }

???????? ~Leaf();?????????????????????????????????????????????????????? Leaf::~Leaf()

???????????????????????????????????????????????????????????????????????? {

???????? void Operation();

???????????????????????????????????????????????????????????????????????? }

? protected:

??????????????????????????????????????????????????????????????????????? void Leaf::Operation()

? private:?????????????????????????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????????????? cout<<"Leaf operation....."<<endl;

? };???????????????????????????????????????????????????????????????????? }

? #endif //~_LEAF_H_

??????????????? 代碼片斷7:main.cpp

? //main.cpp

? #include "Component.h"

? #include "Composite.h"

? #include "Leaf.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

?? {

??????? Leaf* l = new Leaf();

???????? l->Operation();

???????? Composite* com = new Composite();

???????? com->Add(l);

???????? com->Operation();

???????? Component* ll = com->GetChild(0);

???????? ll->Operation();

???????? return 0;

? }

??????????????????????????????????????????????? 第? 43?? 頁 共? 105????? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 44-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

?代碼說明

???? Composite? 模式在實現中有一個問題就是要提供對于子節點(Leaf)的管理策略,這里

使用的是 STL???? 中的vector,可以提供其他的實現方式,如數組、鏈表、Hash 表等。

?討論

???? Composite 模式通過和Decorator 模式有著類似的結構圖,但是 Composite 模式旨在構造

類,而 Decorator?? 模式重在不生成子類即可給對象添加職責。Decorator???????????????? 模式重在修飾,而

Composite 模式重在表示。

2.5 Flyweight 模式

?問題

??? 在面向對象系統的設計何實現中,創建對象是最為常見的操作。這里面就有一個問題:

如果一個應用程序使用了太多的對象,就會造成很大的存儲開銷。特別是對于大量輕量級(細

粒度)的對象,比如在文檔編輯器的設計過程中,我們如果為沒有字母創建一個對象的話,

系統可能會因為大量的對象而造成存儲開銷的浪費。例如一個字母“a ”在文檔中出現了

100000 次,而實際上我們可以讓這一萬個字母 “a”共享一個對象,當然因為在不同的位置

可能字母 “a”有不同的顯示效果 (例如字體和大小等設置不同),在這種情況我們可以為將

對象的狀態分為“外部狀態”和“內部狀態”,將可以被共享(不會變化)的狀態作為內部

狀態存儲在對象中,而外部對象 (例如上面提到的字體、大小等)我們可以在適當的時候將

外部對象最為參數傳遞給對象(例如在顯示的時候,將字體、大小等信息傳遞給對象)。

?模式選擇

??? 上面解決問題的方式被稱作Flyweight 模式解決上面的問題,其典型的結構圖為:

????????????????????????????? 第? 44 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 45-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????????????????? 圖2-1:Flyweight Pattern 結構圖

??? 可以從圖 2-1???? 中看出,Flyweight??? 模式中有一個類似 Factory???????? 模式的對象構造工廠

FlyweightFactory,當客戶程序員(Client )需要一個對象時候就會向 FlyweightFactory? 發出

請求對象的消息 GetFlyweight?????? ()消息,FlyweightFactory? 擁有一個管理、存儲對象的“倉

庫”(或者叫對象池,vector???????? 實現),GetFlyweight?? ()消息會遍歷對象池中的對象,如果已

經存在則直接返回給 Client,否則創建一個新的對象返回給 Client 。當然可能也有不想被共

享的對象 (例如結構圖中的UnshareConcreteFlyweight),但不在本模式的講解范圍,故在實

現中不給出。

?實現

?完整代碼示例(code)

???? Flyweight 模式完整的實現代碼(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 45 頁 共? 105 頁????????????????????????? k_eckel

----------------------- Page 46-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 1:Flyweight.h????????????????????????????????????????????? 代碼片斷2:Flyweight.cpp

? //Flyweight.h??????????????????????????????????????????????????? //Flyweight.cpp

?????????????????????????????????????????????????????????????????? #include "Flyweight.h"

? #ifndef _FLYWEIGHT_H_??????????????????????????????????????????? #include <iostream>

? #define _FLYWEIGHT_H_??????????????????????????????????????????? using namespace std;

?????????????????????????????????????????????????????????????????? Flyweight::Flyweight(string intrinsicState)

? #include <string>??????????????????????????????????????????????? {

? using namespace std;?????????????????????????????????????????????????? this->_intrinsicState = intrinsicState;

?????????????????????????????????????????????????????????????????? }

? class Flyweight????????????????????????????????????????????????? Flyweight::~Flyweight()

?? {?????????????????????????????????????????????????????????????? {

? public:????????????????????????????????????????????????????????? }

???????? virtual ~Flyweight();???????????????????????????????????? void????? Flyweight::Operation(const???????? string&

?????????????????????????????????????????????????????????????????? extrinsicState)

???????? virtual? void??? Operation(const????? string&???????????? {

? extrinsicState);???????????????????????????????????????????????? }

?????????????????????????????????????????????????????????????????? string Flyweight::GetIntrinsicState()

???????? string GetIntrinsicState();?????????????????????????????? {

????????????????????????????????????????????????????????????????????????? return this->_intrinsicState;

? protected:?????????????????????????????????????????????????????? }

???????? Flyweight(string intrinsicState);???????????????????????? ConcreteFlyweight::ConcreteFlyweight(string

?????????????????????????????????????????????????????????????????? intrinsicState):Flyweight(intrinsicState)

? private:???????????????????????????????????????????????????????? {

???????? string _intrinsicState;????????????????????????????????????????? cout<<"ConcreteFlyweight

?????????????????????????????????????????????????????????????????? Build....."<<intrinsicState<<endl;

? };?????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????????????????????????? ConcreteFlyweight::~ConcreteFlyweight()

? class ConcreteFlyweight:public Flyweight???????????????????????? {

?? {?????????????????????????????????????????????????????????????? }

? public:????????????????????????????????????????????????????????? void????????? ConcreteFlyweight::Operation(const

???????? ConcreteFlyweight(string intrinsicState);???????????????? string& extrinsicState)

?????????????????????????????????????????????????????????????????? {

???????? ~ConcreteFlyweight();??????????????????????????????????????????? cout<<"ConcreteFlyweight:????????? 內?????? 蘊

?????????????????????????????????????????????????????????????????? ["<<this->GetIntrinsicState()<<"]???????? 外?????? 蘊

??????? void????????? Operation(const????????? string&???????????? ["<<extrinsicState<<"]"<<endl;

? extrinsicState);???????????????????????????????????????????????? }

? protected:

? private:

? };

? #endif //~_FLYWEIGHT_H_

??????????????????????????????????????????????? 第? 46?? 頁 共? 105????? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 47-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????? 代碼片斷 3:FlyweightFactory.h?????????????????????????????????????? 代碼片斷4:FlyweightFactory.cpp

???? //FlyweightFactory.h???????????????????????????????????????????? //FlyweightFactory.cpp

???? #ifndef _FLYWEIGHTFACTORY_H_???????????????????????????????????? #include "FlyweightFactory.h"

???? #define _FLYWEIGHTFACTORY_H_???????????????????????????????????? #include <iostream>

????????????????????????????????????????????????????????????????????? #include <string>

???? #include "Flyweight.h"?????????????????????????????????????????? #include <cassert>

???? #include <string>??????????????????????????????????????????????? using namespace std;

???? #include <vector>

???? using namespace std;???????????????????????????????????????????? using namespace std;

???? class FlyweightFactory?????????????????????????????????????????? FlyweightFactory::FlyweightFactory()

???? {??????????????????????????????????????????????????????????????? {

???? public:????????????????????????????????????????????????????????? }

???????????? FlyweightFactory();????????????????????????????????????? FlyweightFactory::~FlyweightFactory()

????????????????????????????????????????????????????????????????????? {

???????????? ~FlyweightFactory();???????????????????????????????????? }

????????????????????????????????????????????????????????????????????? Flyweight*

??????????? Flyweight*???? GetFlyweight(const?????? string&?????????? FlyweightFactory::GetFlyweight(const????????? string&

???? key);??????????????????????????????????????????????????????????? key)

????????????????????????????????????????????????????????????????????? {

???? protected:???????????????????????????????????????????????????????????? vector<Flyweight*>::iterator??????????? it???? =

????????????????????????????????????????????????????????????????????? _fly.begin();

???? private:

???????????? vector<Flyweight*> _fly;?????????????????????????????????????? for (; it != _fly.end();it++)

???????????????????????????????????????????????????????????????????????????? {

???? };??????????????????????????????????????????????????????????????????????????? //找到了,就一起用,^_^

?????????????????????????????????????????????????????????????????????????????????? if ((*it)->GetIntrinsicState() == key)

?????????????????????????????????????????????????????????????????????????????????? {

???? #endif //~_FLYWEIGHTFACTORY_H_????????????????????????????????????????????????????? cout<<"already?????? created??? by

????????????????????????????????????????????????????????????????????? users...."<<endl;

???????????????????????????????????????????????????????????????????????????????????????? return *it;

?????????????????????????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????????????????????????????????? Flyweight*???????????? fn???????? =??????? new

????????????????????????????????????????????????????????????????????? ConcreteFlyweight(key);

???????????????????????????????????????????????????????????????????????????? _fly.push_back(fn);

???????????????????????????????????????????????????????????????????????????? return fn;

????????????????????????????????????????????????????????????????????? }

????????????????????????????????????????????????? 第? 47??? 頁 共? 105????? 頁???????????????????????????????????????????? k_eckel

----------------------- Page 48-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 5:main.cpp

??? //main.cpp

??? #include "Flyweight.h"

??? #include "FlyweightFactory.h"

??? #include <iostream>

??? using namespace std;

??? int main(int argc,char* argv[])

??? {

???????? FlyweightFactory*????? fc??? =???? new

??? FlyweightFactory();

???????? Flyweight*???????????? fw1??????????? =

??? fc->GetFlyweight("hello");

???????? Flyweight*???????????? fw2??????????? =

??? fc->GetFlyweight("world!");

???????? Flyweight*???????????? fw3??????????? =

??? fc->GetFlyweight("hello");

????????? return 0;

??? }

?代碼說明

???? Flyweight 模式在實現過程中主要是要為共享對象提供一個存放的“倉庫”(對象池),

這里是通過C++ STL 中Vector 容器,當然就牽涉到STL 編程的一些問題 (Iterator 使用等)。

另外應該注意的就是對對象 “倉庫”(對象池)的管理策略 (查找、插入等),這里是通過直

接的順序遍歷實現的,當然我們可以使用其他更加有效的索引策略,例如Hash 表的管理策

略,當時這些細節已經不是Flyweight 模式本身要處理的了。

?討論

???? 我們在 State? 模式和 Strategy? 模式中會產生很多的對象,因此我們可以通過 Flyweight

模式來解決這個問題。

??????????????????????????????????????? 第? 48 頁 共? 105?? 頁??????????????????????????????????? k_eckel

----------------------- Page 49-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

2.6 Facade 模式

?問題

??? 舉一個生活中的小例子,大凡開過學或者畢過業的都會體會到這樣一種郁悶:你要去n

個地方辦理n 個手續(現在大學合并后就更加麻煩,因為可能那n 個地方都隔的比較遠)。

但是實際上我們需要的就是一個最后一道手續的證明而已,對于前面的手續是怎么辦的、到

什么地方去辦理我們都不感興趣。

??? 實際上在軟件系統開發中也經常回會遇到這樣的情況,可能你實現了一些接口 (模塊),

而這些接口 (模塊)都分布在幾個類中 (比如A 和B、C、D ):A 中實現了一些接口,B 中

實現一些接口 (或者A 代表一個獨立模塊,B、C、D 代表另一些獨立模塊)。然后你的客戶

程序員(使用你設計的開發人員)只有很少的要知道你的不同接口到底是在那個類中實現的,

絕大多數只是想簡單的組合你的A-D 的類的接口,他并不想知道這些接口在哪里實現的。

??? 這里的客戶程序員就是上面生活中想辦理手續的郁悶的人!在現實生活中我們可能可以

很快想到找一個人代理所有的事情就可以解決你的問題(你只要維護和他的簡單的一個接口

而已了!),在軟件系統設計開發中我們可以通過一個叫做Fa?ade 的模式來解決上面的問題。

?模式選擇

??? 我們通過Facade 模式解決上面的問題,其典型的結構圖為:

????????????????????????? 圖2-1:Facade Pattern 結構圖

???? Fa?ade 模式的想法、思路和實現都非常簡單,但是其思想卻是非常有意義的。并且Fa?ade

設計模式在實際的開發設計中也是應用最廣、最多的模式之一。

????????????????????????????? 第? 49 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 50-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

??? 一個簡單的例子就是,我在開發Visual CMCS 項目 【注釋1】時候,在Visual CMCS 中

?我們將允許用戶獨立訪問我們的編譯子系統 (詞法、語法、語義、代碼生成模塊),這些都

?是通過特定的類實現的,我們通過使用Fa?ade 模式給用戶提供一個高層的接口,供用戶在

?不想了解編譯器實現的情況下去使用或重用我們的設計和實現。我們將提供一個 Compile

?類作為Fa?ade 對象。

?【注釋1】:Visual CMCS 是筆者主要設計和完成的一個C_minus 語言 (C? 語言的一個子集)

?的編譯系統,該系統可以生成源C-minus 程序的匯編代碼(并且可以獲得編譯中間階段的

?各個輸出,如:詞法、語法、語義中間代碼等。),并可執行。Visual CMCS 將作為一個對

?教學、學習、研究開源的項目,它更加重要的特性是提供了一個框架(framework ),感興

?趣的開發人員可以實現、測試自己感興趣的模塊,而無需實現整個的編譯系統。Visual

?CMCS 采用VC++ 6.0 的界面風格,更多內容請參見Visual CMCS 網站。

?實現

?完整代碼示例(code)

???? Facade 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代

碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 50 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 51-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????? 代碼片斷 1:Fa?ade.h??????????????????????????????????????????? 代碼片斷2:Fa?ade.cpp

???? //Facade.h????????????????????????????????????????????????? //Facade.cpp

???? #ifndef _FACADE_H_????????????????????????????????????????? #include "Facade.h"

???? #define _FACADE_H_????????????????????????????????????????? #include <iostream>

???? class Subsystem1??????????????????????????????????????????? using namespace std;

???? {?????????????????????????????????????????????????????????? Subsystem1::Subsystem1()

???? public:???????????????????????????????????????????????????? {

??????????? Subsystem1();??????????????????????????????????????? }

??????????? ~Subsystem1();?????????????????????????????????????? Subsystem1::~Subsystem1()

??????????? void Operation();??????????????????????????????????? {

???? protected:????????????????????????????????????????????????? }

???? private:??????????????????????????????????????????????????? void Subsystem1::Operation()

???? };????????????????????????????????????????????????????????? {

???? class Subsystem2?????????????????????????????????????????????????? cout<<"Subsystem1 operation.."<<endl;

???? {?????????????????????????????????????????????????????????? }

???? public:???????????????????????????????????????????????????? Subsystem2::Subsystem2()

??????????? Subsystem2();??????????????????????????????????????? {

??????????? ~Subsystem2();?????????????????????????????????????? }

??????????? void Operation();??????????????????????????????????? Subsystem2::~Subsystem2()

???? protected:????????????????????????????????????????????????? {

???? private:??????????????????????????????????????????????????? }

???? };????????????????????????????????????????????????????????? void Subsystem2::Operation()

???? class Facade??????????????????????????????????????????????? {

???? {????????????????????????????????????????????????????????????????? cout<<"Subsystem2 operation.."<<endl;

???? public:???????????????????????????????????????????????????? }

??????????? Facade();??????????????????????????????????????????? Facade::Facade()

??????????? ~Facade();?????????????????????????????????????????? {

??????????? void OperationWrapper();?????????????????????????????????? this->_subs1 = new Subsystem1();

???? protected:??????????????????????????????????????????????????????? this->_subs2 = new Subsystem2();

???? private:??????????????????????????????????????????????????? }

??????????? Subsystem1* _subs1;????????????????????????????????? Facade::~Facade()

??????????? Subsystem2* _subs2;????????????????????????????????? {

???? };???????????????????????????????????????????????????????????????? delete _subs1;

???? #endif //~_FACADE_H_?????????????????????????????????????????????? delete _subs2;

???????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????? void Facade::OperationWrapper()

???????????????????????????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????? this->_subs1->Operation();

??????????????????????????????????????????????????????????????????????? this->_subs2->Operation();

???????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????? 第? 51?? 頁 共? 105???? 頁????????????????????????????????????????? k_eckel

----------------------- Page 52-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????? 代碼片斷 3:main.cpp

?//main.cpp

?#include "Facade.h"

?#include <iostream>

?using namespace std;

? int main(int argc,char* argv[])

? {

????? Facade* f = new Facade();

?????? f->OperationWrapper();

?????? return 0;

? }

?代碼說明

??? Fa?ade 模式的實現很簡單,多余的解釋完全是沒有必要。

?討論

???? Fa?ade 模式在高層提供了一個統一的接口,解耦了系統。設計模式中還有另一種模式

Mediator 也和Fa?ade 有類似的地方。但是 Mediator 主要目的是對象間的訪問的解耦(通訊

時候的協議),具體請參見Mediator 文檔。

2.7 Proxy 模式

?問題

??? 至少在以下集中情況下可以用Proxy 模式解決問題:

??? 1)創建開銷大的對象時候,比如顯示一幅大的圖片,我們將這個創建的過程交給代理

去完成,GoF 稱之為虛代理(Virtual Proxy);

??? 2 )為網絡上的對象創建一個局部的本地代理,比如要操作一個網絡上的一個對象 (網

絡性能不好的時候,問題尤其突出),我們將這個操縱的過程交給一個代理去完成,GoF 稱

之為遠程代理(Remote Proxy );

??? 3)對對象進行控制訪問的時候,比如在Jive 論壇中不同權限的用戶 (如管理員、普通

用戶等)將獲得不同層次的操作權限,我們將這個工作交給一個代理去完成,GoF 稱之為保

護代理(Protection Proxy )。

??? 4 )智能指針 (Smart Pointer ),關于這個方面的內容,建議參看Andrew Koenig 的《C++

??????????????????????????????? 第? 52 頁 共? 105 頁?????????????????????????? k_eckel

----------------------- Page 53-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

沉思錄》中的第 5 章。

?模式選擇

???? Proxy 模式典型的結構圖為:

?????????????????????????? 圖2-1:Proxy Pattern 結構圖

???? 實際上,Proxy 模式的想法非常簡單,

?實現

?完整代碼示例(code)

???? Proxy 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代碼

?(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 53 頁 共? 105 頁????????????????????????? k_eckel

----------------------- Page 54-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????????? 代碼片斷 1:Proxy.h??????????????????????????????????????????????????? 代碼片斷2:Proxy.cpp

? //Proxy.h????????????????????????????????????????????????????????? //Proxy.cpp

? #ifndef _PROXY_H_????????????????????????????????????????????????? #include "Proxy.h"

? #define _PROXY_H_????????????????????????????????????????????????? #include <iostream>

? class Subject????????????????????????????????????????????????????? using namespace std;

?? {???????????????????????????????????????????????????????????????? Subject::Subject()

? public:???????????????????????????????????????????????????????????? {

????????? virtual ~Subject();??????????????????????????????????????? }

???????? virtual void Request() = 0;???????????????????????????????? Subject::~Subject()

? protected:????????????????????????????????????????????????????????? {

????????? Subject();???????????????????????????????????????????????? }

? private:?????????????????????????????????????????????????????????? ConcreteSubject::ConcreteSubject()

? };????????????????????????????????????????????????????????????????? {

? class ConcreteSubject:public Subject?????????????????????????????? }

?? {???????????????????????????????????????????????????????????????? ConcreteSubject::~ConcreteSubject()

? public:???????????????????????????????????????????????????????????? {

????????? ConcreteSubject();???????????????????????????????????????? }

????????? ~ConcreteSubject();??????????????????????????????????????? void ConcreteSubject::Request()

????????? void Request();???????????????????????????????????????????? {

? protected:???????????????????????????????????????????????????????????????? cout<<"ConcreteSubject......request...."<<

? private:?????????????????????????????????????????????????????????? endl;

? };???????????????????????????????????????????????????????????????? }

? class Proxy??????????????????????????????????????????????????????? Proxy::Proxy()

?? {????????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????????? }

????????? Proxy();?????????????????????????????????????????????????? Proxy::Proxy(Subject* sub)

????????? Proxy(Subject* sub);??????????????????????????????????????? {

????????? ~Proxy();???????????????????????????????????????????????????????? _sub = sub;

????????? void Request();??????????????????????????????????????????? }

? protected:???????????????????????????????????????????????????????? Proxy::~Proxy()

????????? private:??????????????????????????????????????????????????? {

????????? Subject* _sub;???????????????????????????????????????????????????? delete _sub;

? };???????????????????????????????????????????????????????????????? }

? #endif //~_PROXY_H_??????????????????????????????????????????????? void Proxy::Request()

????????????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????????????? cout<<"Proxy request...."<<endl;

???????????????????????????????????????????????????????????????????????????? _sub->Request();

???????????????????????????????????????????????????????????????????? }

????????????????????????????????????????????????? 第? 54?? 頁 共? 105????? 頁???????????????????????????????????????????? k_eckel

----------------------- Page 55-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????? 代碼片斷 3:main.cpp

?//main.cpp

?#include "Proxy.h"

?#include <iostream>

?using namespace std;

?int main(int argc,char* argv[])

? {

????? Subject* sub = new ConcreteSubject();

????? Proxy* p = new Proxy(sub);

?????? p->Request();

?????? return 0;

? }

?代碼說明

??? Proxy 模式的實現很簡單,這里不做多余解釋。

??? 可以看到,示例代碼運行后,p? 的Request 請求實際上是交給了sub 來實際執行。

?討論

???? Proxy 模式最大的好處就是實現了邏輯和實現的徹底解耦。

3?? 行為模式

3.1 Template 模式

?問題

??? 在面向對象系統的分析與設計過程中經常會遇到這樣一種情況:對于某一個業務邏輯

?(算法實現)在不同的對象中有不同的細節實現,但是邏輯 (算法)的框架 (或通用的應用

算法)是相同的。Template 提供了這種情況的一個實現框架。

??? Template 模式是采用繼承的方式實現這一點:將邏輯 (算法)框架放在抽象基類中,并

定義好細節的接口,子類中實現細節。【注釋1】

?【注釋1】:Strategy 模式解決的是和Template 模式類似的問題,但是 Strategy 模式是將邏輯

?(算法)封裝到一個類中,并采取組合(委托)的方式解決這個問題。

?模式選擇

?????????????????????????????? 第? 55 頁 共? 105 頁?????????????????????????? k_eckel

----------------------- Page 56-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??? 解決2.1 中問題可以采取兩種模式來解決,一是Template 模式,二是 Strategy 模式。本

文當給出的是Template 模式。一個通用的Template 模式的結構圖為:

?????????????????????????? 圖2-1:Template 模式結構圖

??? Template 模式實際上就是利用面向對象中多態的概念實現算法實現細節和高層接口的

松耦合。可以看到 Template? 模式采取的是繼承方式實現這一點的,由于繼承是一種強約束

性的條件,因此也給 Template? 模式帶來一些許多不方便的地方(有關這一點將在討論中展

開)。

?實現

?完整代碼示例(code)

???? Template 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代

碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 56 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 57-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????? 代碼片斷 1:Template.h??????????????????????????????????????????? 代碼片斷2:Template.cpp

? //Template.h?????????????????????????????????????????????????? #include "Template.h"

? #ifndef _TEMPLATE_H_?????????????????????????????????????????? #include <iostream>

? #define _TEMPLATE_H_?????????????????????????????????????????? using namespace std;

? class AbstractClass??????????????????????????????????????????? AbstractClass::AbstractClass()

? {????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????? }

???????? virtual ~AbstractClass();?????????????????????????????? AbstractClass::~AbstractClass()

???????? void TemplateMethod();????????????????????????????????? {

? protected:???????????????????????????????????????????????????? }

??????? virtual void PrimitiveOperation1() = 0;????????????????? void AbstractClass::TemplateMethod()

??????? virtual void PrimitiveOperation2() = 0;????????????????? {

??????? AbstractClass();?????????????????????????????????????????????? this->PrimitiveOperation1();

? private:???????????????????????????????????????????????????????????? this->PrimitiveOperation2();

? };???????????????????????????????????????????????????????????? }

? class ConcreteClass1:public AbstractClass????????????????????? ConcreteClass1::ConcreteClass1()

? {????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????? }

???????? ConcreteClass1();?????????????????????????????????????? ConcreteClass1::~ConcreteClass1()

???????? ~ConcreteClass1();????????????????????????????????????? {

? protected:???????????????????????????????????????????????????? }

???????? void PrimitiveOperation1();???????????????????????????? void ConcreteClass1::PrimitiveOperation1()

???????? void PrimitiveOperation2();???????????????????????????? {

? private:???????????????????????????????????????????????????????????? cout<<"ConcreteClass1...PrimitiveOperat

? };?????????????????????????????????????????????????????????????????????? ion1"<<endl;

? class ConcreteClass2:public AbstractClass????????????????????? }

? {????????????????????????????????????????????????????????????? void ConcreteClass1::PrimitiveOperation2()

? public:??????????????????????????????????????????????????????? {

???????? ConcreteClass2();???????????????????????????????????????????? cout<<"ConcreteClass1...PrimitiveOperat

???????? ~ConcreteClass2();????????????????????????????????????????????? ion2"<<endl;

? protected:???????????????????????????????????????????????????? }

???????? void PrimitiveOperation1();???????????????????????????? ConcreteClass2::ConcreteClass2()

???????? void PrimitiveOperation2();???????????????????????????? {

? private:?????????????????????????????????????????????????????? }

? };???????????????????????????????????????????????????????????? ConcreteClass2::~ConcreteClass2()

? #endif //~ TEMPLATE? H???????????????????????????????????????? {

???????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????? void ConcreteClass2::PrimitiveOperation1()

???????????????????????????????????????????????????????????????? {

?????????????????????????????????????????????????????????????????????? cout<<"ConcreteClass2...PrimitiveOperat

???????????????????????????????????????????????????????????????????????? ion1"<<endl;

???????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????? void ConcreteClass2::PrimitiveOperation2()

???????????????????????????????????????????????????????????????? {

?????????????????????????????????????????????????????????????????????? cout<<"ConcreteClass2...PrimitiveOperat
???????????????????????????????????????????? 第? 57? 頁 共? 105???? 頁?????? ion2"<<endl;???????????????????? k_eckel

???????????????????????????????????????????????????????????????? }

----------------------- Page 58-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????? 代碼片斷 3:main.cpp//測試程序

? #include "Template.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

? AbstractClass* p1 = new ConcreteClass1();

? AbstractClass* p2 = new ConcreteClass2();

?????? p1->TemplateMethod();

?????? p2->TemplateMethod();

?????? return 0;

? }

?代碼說明

???? 由于 Template? 模式的實現代碼很簡單,因此解釋是多余的。其關鍵是將通用算法(邏

輯)封裝起來,而將算法細節讓子類實現(多態)。

??? 唯一注意的是我們將原語操作 (細節算法)定義未保護 (Protected)成員,只供模板方

法調用(子類可以)。

?討論

???? Template 模式是很簡單模式,但是也應用很廣的模式。如上面的分析和實現中闡明的

Template 是采用繼承的方式實現算法的異構,其關鍵點就是將通用算法封裝在抽象基類中,

并將不同的算法細節放到子類中實現。

???? Template 模式獲得一種反向控制結構效果,這也是面向對象系統的分析和設計中一個原

則DIP?? (依賴倒置:Dependency Inversion Principles )。其含義就是父類調用子類的操作 (高

層模塊調用低層模塊的操作),低層模塊實現高層模塊聲明的接口。這樣控制權在父類(高

層模塊),低層模塊反而要依賴高層模塊。

??? 繼承的強制性約束關系也讓 Template????????????????? 模式有不足的地方,我們可以看到對于

ConcreteClass? 類中的實現的原語方法 Primitive1(),是不能被別的類復用。假設我們要創建

一個 AbstractClass? 的變體 AnotherAbstractClass,并且兩者只是通用算法不一樣,其原語操

作想復用 AbstractClass? 的子類的實現。但是這是不可能實現的,因為ConcreteClass 繼承自

AbstractClass,也就繼承了 AbstractClass????? 的通用算法,AnotherAbstractClass?????? 是復用不了

ConcreteClass 的實現,因為后者不是繼承自前者。

??? Template 模式暴露的問題也正是繼承所固有的問題,Strategy 模式則通過組合(委托)

??????????????????????????????? 第? 58 頁 共? 105 頁??????????????????????????? k_eckel

----------------------- Page 59-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

來達到和Template 模式類似的效果,其代價就是空間和時間上的代價,關于 Strategy 模式的

詳細討論請參考 Strategy 模式解析。

3.2 Strategy 模式

?問題

??? Strategy 模式和Template 模式要解決的問題是相同(類似)的,都是為了給業務邏輯(算

法)具體實現和抽象接口之間的解耦。Strategy 模式將邏輯 (算法)封裝到一個類 (Context )

里面,通過組合的方式將具體算法的實現在組合對象中實現,再通過委托的方式將抽象接口

的實現委托給組合對象實現。State 模式也有類似的功能,他們之間的區別將在討論中給出。

?模式選擇

???? Strategy 模式典型的結構圖為:

????????????????????????? 圖2-1:Strategy Pattern 結構圖

???? 這里的關鍵就是將算法的邏輯抽象接口(DoAction )封裝到一個類中(Context ),再

?通過委托的方式將具體的算法實現委托給具體的 Strategy 類來實現(ConcreteStrategeA

?類)。

?實現

?完整代碼示例(code)

???? Strategy 模式實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代碼

?(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 59 頁 共? 105 頁??????????????????????? k_eckel

----------------------- Page 60-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 1:strategy.h????????????????????????????????????????????????? 代碼片斷2:strategy.cpp

? //strategy.h??????????????????????????????????????????????????????? //Strategy.cpp

? #ifndef _STRATEGY_H_??????????????????????????????????????????????? #include "Strategy.h"

? #define _STRATEGY_H_??????????????????????????????????????????????? #include <iostream>

? class Strategy????????????????????????????????????????????????????? using namespace std;

?? {????????????????????????????????????????????????????????????????? Strategy::Strategy()

? public:???????????????????????????????????????????????????????????? {

???????? Strategy();????????????????????????????????????????????????? }

???????? virtual ~Strategy();???????????????????????????????????????? Strategy::~Strategy()

??????? virtual void AlgrithmInterface() = 0;???????????????????????? {

? protected:???????????????????????????????????????????????????????????????? cout<<"~Strategy....."<<endl;

? private:??????????????????????????????????????????????????????????? }

? };????????????????????????????????????????????????????????????????? void Strategy::AlgrithmInterface()

? class ConcreteStrategyA:public Strategy???????????????????????????? {

?? {????????????????????????????????????????????????????????????????? }

? public:???????????????????????????????????????????????????????????? ConcreteStrategyA::ConcreteStrategyA()

???????? ConcreteStrategyA();???????????????????????????????????????? {

???????? virtual ~ConcreteStrategyA();??????????????????????????????? }

???????? void AlgrithmInterface();??????????????????????????????????? ConcreteStrategyA::~ConcreteStrategyA()

? protected:????????????????????????????????????????????????????????? {

? private:?????????????????????????????????????????????????????????????????? cout<<"~ConcreteStrategyA....."<<endl;

? };????????????????????????????????????????????????????????????????? }

? class ConcreteStrategyB:public Strategy???????????????????????????? void ConcreteStrategyA::AlgrithmInterface()

?? {????????????????????????????????????????????????????????????????? {

? public:??????????????????????????????????????????????????????????????????? cout<<"test

???????? ConcreteStrategyB();???????????????????????????????????????? ConcreteStrategyA....."<<endl;

???????? virtual ~ConcreteStrategyB();??????????????????????????????? }

???????? void AlgrithmInterface();??????????????????????????????????? ConcreteStrategyB::ConcreteStrategyB()

? protected:????????????????????????????????????????????????????????? {

? private:??????????????????????????????????????????????????????????? }

? };????????????????????????????????????????????????????????????????? ConcreteStrategyB::~ConcreteStrategyB()

? #endif //~_STRATEGY_H_????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????????????? cout<<"~ConcreteStrategyB....."<<endl;

????????????????????????????????????????????????????????????????????? }

????????????????????????????????????????????????????????????????????? void ConcreteStrategyB::AlgrithmInterface()

????????????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????????????? cout<<"test

????????????????????????????????????????????????????????????????????? ConcreteStrategyB....."<<endl;

????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????? 第? 60?? 頁 共? 105????? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 61-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????????? 代碼片斷 3:Context.h???????????????????????????????????????????? 代碼片斷4:Context.cpp

??? //Context.h??????????????????????????????????????????????????? //Context.cpp

??? #ifndef _CONTEXT_H_??????????????????????????????????????????? #include "Context.h"

??? #define _CONTEXT_H_??????????????????????????????????????????? #include "Strategy.h"

?????????????????????????????????????????????????????????????????? #include <iostream>

???? class Strategy;?????????????????????????????????????????????? using namespace std;

??? /**

???? *這個類是Strategy 模式的關鍵,也是Strategy??????????????????????????????? Context::Context(Strategy* stg)

???? 模式和Template 模式的根本區別所在。???????????????????????????????????????? {

???? *Strategy 通過 “組合”(委托)方式實現算法???????????????????????????????????????? _stg = stg;

????? (實現)的異構,而Template 模式則采取的????????????????????????????????????? }

???? 是繼承的方式

???? *這兩個模式的區別也是繼承和組合兩種實?????????????????????????????????????????? Context::~Context()

???? 現接口重用的方式的區別??????????????????????????????????????????????????? {

???? */?????????????????????????????????????????????????????????????????? if (!_stg)

???? class Context???????????????????????????????????????????????????????????? delete _stg;

???? {????????????????????????????????????????????????????????????? }

??? public:

?????????? Context(Strategy* stg);???????????????????????????????? void Context::DoAction()

??????????????????????????????????????????????????????????????????? {

?????????? ~Context();??????????????????????????????????????????????????? _stg->AlgrithmInterface();

??????????????????????????????????????????????????????????????????? }

?????????? void DoAction();

??? protected:

??? private:

?????????? Strategy* _stg;

???? };

??? #endif //~_CONTEXT_H_

??????????????????????????????????????????? 第? 61?? 頁 共? 105??? 頁??????????????????????????????????????? k_eckel

----------------------- Page 62-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 5:main.cpp

????? //main.cpp

????? #include "Context.h"

????? #include "Strategy.h"

????? #include <iostream>

????? using namespace std;

????? int main(int argc,char* argv[])

????? {

?????????? Strategy* ps;

????????? ps = new ConcreteStrategyA();

????????? Context* pc = new Context(ps);

?????????? pc->DoAction();

????????? if (NULL != pc)

?????????????? delete pc;

?????????? return 0;

????? }

?代碼說明

???? Strategy 模式的代碼很直觀,關鍵是將算法的邏輯封裝到一個類中。

?討論

??? 可以看到 Strategy 模式和 Template 模式解決了類似的問題,也正如在 Template 模式中

分析的,Strategy 模式和Template 模式實際是實現一個抽象接口的兩種方式:繼承和組合之

間的區別。要實現一個抽象接口,繼承是一種方式:我們將抽象接口聲明在基類中,將具體

的實現放在具體子類中。組合 (委托)是另外一種方式:我們將接口的實現放在被組合對象

中,將抽象接口放在組合類中。這兩種方式各有優缺點,先列出來:

???? 1)繼承:

????????? 優點

???????? 1)易于修改和擴展那些被復用的實現。

????????? 缺點

???????? 1)破壞了封裝性,繼承中父類的實現細節暴露給子類了;

???????? 2 )“白盒”復用,原因在 1)中;

???????? 3)當父類的實現更改時,其所有子類將不得不隨之改變

???????? 4 )從父類繼承而來的實現在運行期間不能改變(編譯期間就已經確定了)。

????????????????????????????????? 第? 62 頁 共? 105 頁?????????????????????????????? k_eckel

----------------------- Page 63-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

??? 2 )組合

???????? 優點

??????? 1)“黑盒”復用,因為被包含對象的內部細節對外是不可見的;

??????? 2 )封裝性好,原因為 1);

??????? 3)實現和抽象的依賴性很小(組合對象和被組合對象之間的依賴性小);

??????? 4 )可以在運行期間動態定義實現(通過一個指向相同類型的指針,典型的是抽象

??????? 基類的指針)。

???????? 缺點

??????? 1)系統中對象過多。

??????? 從上面對比中我們可以看出,組合相比繼承可以取得更好的效果,因此在面向對象

??? 的設計中的有一條很重要的原則就是:優先使用 (對象)組合,而非 (類)繼承 (Favor

??? Composition Over Inheritance)。

??????? 實際上,繼承是一種強制性很強的方式,因此也使得基類和具體子類之間的耦合

??? 性很強。例如在Template 模式中在 ConcreteClass1 中定義的原語操作別的類是不能夠直

??? 接復用 (除非你繼承自AbstractClass,具體分析請參看Template 模式文檔)。而組合 (委

??? 托)的方式則有很小的耦合性,實現 (具體實現)和接口 (抽象接口)之間的依賴性很

??? 小,例如在本實現中,ConcreteStrategyA 的具體實現操作很容易被別的類復用,例如我

??? 們要定義另一個 Context 類 AnotherContext,只要組合一個指向 Strategy? 的指針就可以

??? 很容易地復用ConcreteStrategyA 的實現了。

??????? 我們在Bridge 模式的問題和Bridge 模式的分析中,正是說明了繼承和組合之間的

??? 區別。請參看相應模式解析。

??????? 另外Strategy 模式很 State 模式也有相似之處,但是 State 模式注重的對象在不同的

??? 狀態下不同的操作。兩者之間的區別就是 State 模式中具體實現類中有一個指向Context

??? 的引用,而Strategy 模式則沒有。具體分析請參看相應的 State 模式分析中。

3.3 State 模式

?問題

??? 每個人、事物在不同的狀態下會有不同表現(動作),而一個狀態又會在不同的表現下

????????????????????????????? 第? 63 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 64-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

轉移到下一個不同的狀態 (State)。最簡單的一個生活中的例子就是:地鐵入口處,如果你

放入正確的地鐵票,門就會打開讓你通過。在出口處也是驗票,如果正確你就可以 ok,否

則就不讓你通過(如果你動作野蠻,或許會有報警(Alarm ),:))。

??? 有限狀態自動機 (FSM )也是一個典型的狀態不同,對輸入有不同的響應 (狀態轉移)。

通常我們在實現這類系統會使用到很多的 Switch/Case 語句,Case 某種狀態,發生什么動作,

Case 另外一種狀態,則發生另外一種狀態。但是這種實現方式至少有以下兩個問題:

??? 1)當狀態數目不是很多的時候,Switch/Case 可能可以搞定。但是當狀態數目很多的時

候 (實際系統中也正是如此),維護一大組的 Switch/Case 語句將是一件異常困難并且容易出

錯的事情。

??? 2 )狀態邏輯和動作實現沒有分離。在很多的系統實現中,動作的實現代碼直接寫在狀

態的邏輯當中。這帶來的后果就是系統的擴展性和維護得不到保證。

?模式選擇

???? State 模式就是被用來解決上面列出的兩個問題的,在 State 模式中我們將狀態邏輯和動

作實現進行分離。當一個操作中要維護大量的 case? 分支語句,并且這些分支依賴于對象的

狀態。State 模式將每一個分支都封裝到獨立的類中。State 模式典型的結構圖為:

?????????????????????????? 圖2-1:State Pattern 結構圖

?實現

?完整代碼示例(code)

???? State 模式實現上還是有些特點,這里為了方便初學者的學習和參考,將給出完整的實

????????????????????????????? 第? 64 頁 共? 105 頁??????????????????????? k_eckel

----------------------- Page 65-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

現代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????? 代碼片斷 1:State.h?????????????????????????????????????????????????????? 代碼片斷2:State.cpp

? //state.h????????????????????????????????????????????????????????????? //State.cpp

? #ifndef _STATE_H_????????????????????????????????????????????????????? #include "State.h"

? #define _STATE_H_????????????????????????????????????????????????????? #include "Context.h"

? class Context; //前置聲明????????????????????????????????????????????????? #include <iostream>

? class State??????????????????????????????????????????????????????????? using namespace std;

?? {???????????????????????????????????????????????????????????????????? State::State()

? public:??????????????????????????????????????????????????????????????? {

????????? State();?????????????????????????????????????????????????????? }

????????? virtual ~State();????????????????????????????????????????????? State::~State()

????????? virtual?????????????????????????????????? void???????????????? {

? OperationInterface(Context* ) = 0;???????????????????????????????????? }

????????? virtual?????????????????????????????????? void???????????????? void State::OperationInterface(Context* con)

? OperationChangeState(Context*) = 0;??????????????????????????????????? {

? protected:??????????????????????????????????????????????????????????????????? cout<<"State::.."<<endl;

???????? bool???? ChangeState(Context*??????? con,State*???????????????? }

? st);?????????????????????????????????????????????????????????????????? bool State::ChangeState(Context* con,State* st)

???????????????????????????????????????????????????????????????????????? {

? private:????????????????????????????????????????????????????????????????????? con->ChangeState(st);

???????? //bool?? ChangeState(Context*??????? con,State*??????????????????????? return true;

? st);?????????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????????????? void?????? State::OperationChangeState(Context*

?? };??????????????????????????????????????????????????????????????????? con)

???????????????????????????????????????????????????????????????????????? {

? class ConcreteStateA:public State????????????????????????????????????? }

?? {???????????????????????????????????????????????????????????????????? ConcreteStateA::ConcreteStateA()

? public:??????????????????????????????????????????????????????????????? {

????????? ConcreteStateA();????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????????????? ConcreteStateA::~ConcreteStateA()

????????? virtual ~ConcreteStateA();???????????????????????????????????? {

???????????????????????????????????????????????????????????????????????? }

????????? virtual?????????????????????????????????? void???????????????? void

? OperationInterface(Context* );???????????????????????????????????????? ConcreteStateA::OperationInterface(Context*

???????????????????????????????????????????????????????????????????????? con)

????????? virtual?????????????????????????????????? void???????????????? {

? OperationChangeState(Context*);?????????????????????????????????????????????? cout<<"ConcreteStateA::OperationInterfa

???????????????????????????????????????????????????????????????????????? ce......"<<endl;

? protected:???????????????????????????????????????????????????????????? }

? private:

?? };

????????????????????????????????????????????????? 第? 65??? 頁 共? 105????? 頁???????????????????????????????????????????? k_eckel

----------------------- Page 66-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????????? 代碼片斷 1:State.h????????????????????????????????????????????????? 代碼片斷2:State.cpp

???? class ConcreteStateB:public State???????????????????????????????? void

???? {???????????????????????????????????????????????????????????????? ConcreteStateA::OperationChangeState(Contex

???? public:?????????????????????????????????????????????????????????? t* con)

??????????? ConcreteStateB();????????????????????????????????????????? {

??????????? virtual ~ConcreteStateB();??????????????????????????????????????? OperationInterface(con);

??????????? virtual????????????????????????????????? void???????????????????? this->ChangeState(con,new

???? OperationInterface(Context* );??????????????????????????????????? ConcreteStateB());

??????????? virtual????????????????????????????????? void????????????? }

???? OperationChangeState(Context*);

???? protected:??????????????????????????????????????????????????????? ConcreteStateB::ConcreteStateB()

???? private:????????????????????????????????????????????????????????? {

???? };??????????????????????????????????????????????????????????????? }

???? #endif //~_STATE_H_?????????????????????????????????????????????? ConcreteStateB::~ConcreteStateB()

?????????????????????????????????????????????????????????????????????? {

?????????????????????????????????????????????????????????????????????? }

????????????????? 代碼片斷 3:Context.h???????????????????????????????????? void

???? //context.h?????????????????????????????????????????????????????? ConcreteStateB::OperationInterface(Context*

???? #ifndef _CONTEXT_H_?????????????????????????????????????????????? con)

???? #define _CONTEXT_H_?????????????????????????????????????????????? {

???? class State;???????????????????????????????????????????????????????????? cout<<"ConcreteStateB::OperationInterfa

???? class Context???????????????????????????????????????????????????? ce......"<<endl;

???? {???????????????????????????????????????????????????????????????? }

???? public:?????????????????????????????????????????????????????????? void

??????????? Context();???????????????????????????????????????????????? ConcreteStateB::OperationChangeState(Contex

??????????? Context(State* state);???????????????????????????????????? t* con)

??????????? ~Context();??????????????????????????????????????????????? {

??????????? void OprationInterface();???????????????????????????????????????? OperationInterface(con);

??????????? void OperationChangState();?????????????????????????????????????? this->ChangeState(con,new

???? protected:??????????????????????????????????????????????????????? ConcreteStateA());

???? private:????????????????????????????????????????????????????????? }

?????????? friend? class?? State;?? //表明在 State 類中可

???? 以訪問Context 類的private 字段

?????????? bool ChangeState(State* state);

???? private:

??????????? State* _state;

???? };

???? #endif //~_CONTEXT_H_

???????????????????????????????????????????????? 第? 66?? 頁 共? 105????? 頁??????????????????????????????????????????? k_eckel

----------------------- Page 67-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????????????????????????????????????????????????????????????????????? 代碼片斷4:Context.cpp

??????????????????????????????????????????????????????????????????? //context.cpp

??????????????????????????????????????????????????????????????????? #include "Context.h"

??????????????????????????????????????????????????????????????????? #include "State.h"

??????????????????????????????????????????????????????????????????? Context::Context()

???????????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????????????????????????? Context::Context(State* state)

???????????????????????????????????????????????????????????????????? {
?????????????? 代碼片斷 5:main.cpp
?????????????????????????????????????????????????????????????????????????? this->_state = state;
? //main.cpp
???????????????????????????????????????????????????????????????????? }
? #include "Context.h"
??????????????????????????????????????????????????????????????????? Context::~Context()
? #include "State.h"
???????????????????????????????????????????????????????????????????? {
? #include <iostream>
?????????????????????????????????????????????????????????????????????????? delete _state;
? using namespace std;
???????????????????????????????????????????????????????????????????? }
? int main(int argc,char* argv[])
??????????????????????????????????????????????????????????????????? void Context::OprationInterface()
? {
???????????????????????????????????????????????????????????????????? {
??????? State* st = new ConcreteStateA();
?????????????????????????????????????????????????????????????????????????? _state->OperationInterface(this);
??????? Context* con = new Context(st);
???????????????????????????????????????????????????????????????????? }
???????? con->OprationInterface();
??????????????????????????????????????????????????????????????????? bool Context::ChangeState(State* state)
??????? con-> OprationInterface ();
???????????????????????????????????????????????????????????????????? {
???????? con->OprationInterface();
?????????????????????????????????????????????????????????????????????????? this->_state = state;
??????? if (con != NULL)
?????????????????????????????????????????????????????????????????????????? return true;
????????????? delete con;
???????????????????????????????????????????????????????????????????? }
??????? if (st != NULL)

????????????? st = NULL;
??????????????????????????????????????????????????????????????????? void Context::OperationChangState()
???????? return 0;
???????????????????????????????????????????????????????????????????? {
? }
?????????????????????????????????????????????????????????????????????????? _state->OperationChangeState(this);

???????????????????????????????????????????????????????????????????? }

?代碼說明

?????? State 模式在實現中,有兩個關鍵點:

?????? 1 )將State 聲明為Context 的友元類 (friend class),其作用是讓 State 模式訪問 Context

的protected 接口 ChangeSate????????????? ()。

?????? 2 )State 及其子類中的操作都將 Context*傳入作為參數,其主要目的是 State 類可以通

過這個指針調用Context 中的方法(在本示例代碼中沒有體現)。這也是 State 模式和 Strategy

模式的最大區別所在。

????? 運行了示例代碼后可以獲得以下的結果:連續 3 次調用了Context 的OprationInterface????????????????????????????????????????????????????? ()

因為每次調用后狀態都會改變(A-B-A ),因此該動作隨著Context 的狀態的轉變而獲得了不同的結果。

???????????????????????????????????????????? 第? 67?? 頁 共? 105??? 頁???????????????????????????????????????? k_eckel

----------------------- Page 68-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

?討論

???? State 模式的應用也非常廣泛,從最高層邏輯用戶接口 GUI 到最底層的通訊協議(例如

GoF 在《設計模式》中就利用 State 模式模擬實現一個TCP 連接的類。)都有其用武之地。

???? State 模式和 Strategy 模式又很大程度上的相似:它們都有一個Context 類,都是通過委

托 (組合)給一個具有多個派生類的多態基類實現Context 的算法邏輯。兩者最大的差別就

是State 模式中派生類持有指向Context 對象的引用,并通過這個引用調用Context 中的方法,

但在 Strategy 模式中就沒有這種情況。因此可以說一個 State 實例同樣是 Strategy 模式的一

個實例,反之卻不成立。實際上 State 模式和 Strategy 模式的區別還在于它們所關注的點不

盡相同:State??? 模式主要是要適應對象對于狀態改變時的不同處理策略的實現,而 Strategy

則主要是具體算法和實現接口的解耦 (coupling ),Strategy 模式中并沒有狀態的概念 (雖然

很多時候有可以被看作是狀態的概念),并且更加不關心狀態的改變了。

???? State 模式很好地實現了對象的狀態邏輯和動作實現的分離,狀態邏輯分布在 State 的派

生類中實現,而動作實現則可以放在 Context 類中實現(這也是為什么 State 派生類需要擁

有一個指向Context 的指針)。這使得兩者的變化相互獨立,改變State 的狀態邏輯可以很容

易復用Context 的動作,也可以在不影響 State 派生類的前提下創建 Context 的子類來更改或

替換動作實現。

???? State 模式問題主要是邏輯分散化,狀態邏輯分布到了很多的 State 的子類中,很難看到

整個的狀態邏輯圖,這也帶來了代碼的維護問題。

3.4 Observer 模式

?問題

???? Observer? 模式應該可以說是應用最多、影響最廣的模式之一,因為 Observer? 的一個實

例Model/View/Control (MVC )結構在系統開發架構設計中有著很重要的地位和意義,MVC

實現了業務邏輯和表示層的解耦。個人也認為Observer 模式是軟件開發過程中必須要掌握

和使用的模式之一。在MFC? 中,Doc/View??????????? (文檔視圖結構)提供了實現MVC 的框架結構

?(有一個從設計模式(Observer 模式)的角度分析分析Doc/View 的文章正在進一步的撰寫

當中,遺憾的是時間:))。在Java 陣容中,Struts 則提供和MFC 中Doc/View 結構類似的實

????????????????????????????? 第? 68 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 69-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

現 MVC? 的框架。另外 Java 語言本身就提供了 Observer 模式的實現接口,這將在討論中給

出。

??? 當然,MVC 只是Observer 模式的一個實例。Observer 模式要解決的問題為:建立一個

一(Subject )對多(Observer)的依賴關系,并且做到當 “一”變化的時候,依賴這個 “一”

的多也能夠同步改變。最常見的一個例子就是:對同一組數據進行統計分析時候,我們希望

能夠提供多種形式的表示(例如以表格進行統計顯示、柱狀圖統計顯示、百分比統計顯示等)。

這些表示都依賴于同一組數據,我們當然需要當數據改變的時候,所有的統計的顯示都能夠

同時改變。Observer 模式就是解決了這一個問題。

?模式選擇

???? Observer 模式典型的結構圖為:

???????????????????????? 圖2-1:Observer Pattern 結構圖

??? 這里的目標 Subject 提供依賴于它的觀察者 Observer 的注冊 (Attach)和注銷 (Detach )

操作,并且提供了使得依賴于它的所有觀察者同步的操作(Notify )。觀察者 Observer? 則提

供一個Update 操作,注意這里的Observer 的Update 操作并不在Observer 改變了Subject? 目

標狀態的時候就對自己進行更新,這個更新操作要延遲到 Subject 對象發出Notify 通知所有

Observer 進行修改(調用Update )。

?實現

?完整代碼示例(code)

???? Observer 模式的實現有些特點,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 69 頁 共? 105 頁??????????????????????? k_eckel

----------------------- Page 70-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????? 代碼片斷 1:Subject.h????????????????????????????????????????????????? 代碼片斷2:Subject.cpp

? //Subject.h???????????????????????????????????????????????????????? #include "Subject.h"

? #ifndef _SUBJECT_H_???????????????????????????????????????????????? #include "Observer.h"

? #define _SUBJECT_H_???????????????????????????????????????????????? #include <iostream>

? #include <list>???????????????????????????????????????????????????? #include <list>

? #include <string>?????????????????????????????????????????????????? using namespace std;

? using namespace std;??????????????????????????????????????????????? typedef string state;

? typedef string State;?????????????????????????????????????????????? Subject::Subject()

? class Observer;???????????????????????????????????????????????????? {???? //在模板的使用之前一定要new,創建

? class Subject???????????????????????????????????????????????????????????? _obvs = new list<Observer*>;

?? {????????????????????????????????????????????????????????????????? }

? public:???????????????????????????????????????????????????????????? Subject::~Subject()

????????? virtual ~Subject();???????????????????????????????????????? { }

???????? virtual void Attach(Observer* obv);????????????????????????? void Subject::Attach(Observer* obv)

???????? virtual void Detach(Observer* obv);????????????????????????? {

???????? virtual void Notify();????????????????????????????????????????????? _obvs->push_front(obv);

???????? virtual void SetState(const State& st) = 0;????????????????? }

???????? virtual State GetState() = 0;??????????????????????????????? void Subject::Detach(Observer* obv)

? protected:????????????????????????????????????????????????????????? {

????????? Subject();??????????????????????????????????????????????????????? if (obv != NULL)

? private:???????????????????????????????????????????????????????????????????????? _obvs->remove(obv);

???????? list<Observer* >* _obvs;???????????????????????????????????? }

? };????????????????????????????????????????????????????????????????? void Subject::Notify()

? class ConcreteSubject:public Subject??????????????????????????????? {

?? {???????????????????????????????????????????????????????????????????????? list<Observer*>::iterator it;

? public:??????????????????????????????????????????????????????????????????? it = _obvs->begin();

????????? ConcreteSubject();??????????????????????????????????????????????? for (;it != _obvs->end();it++)

????????? ~ConcreteSubject();??????????????????????????????????????????????? {??? //關于模板和iterator 的用法

????????? State GetState();??????????????????????????????????????????????????????? (*it)->Update(this);

???????? void SetState(const State& st);???????????????????????????????????? }

? protected:????????????????????????????????????????????????????????? }

? private:??????????????????????????????????????????????????????????? ConcreteSubject::ConcreteSubject()

????????? State _st;????????????????????????????????????????????????? {

? };???????????????????????????????????????????????????????????????????????? _st = '/0';

????????????????????????????????????????????????????????????????????? }

? #endif //~_SUBJECT_H_?????????????????????????????????????????????? ConcreteSubject::~ConcreteSubject()

????????????????????????????????????????????????????????????????????? { }

????????????????????????????????????????????????????????????????????? State ConcreteSubject::GetState()

????????????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????????????? return _st;

????????????????????????????????????????????????????????????????????? }

????????????????????????????????????????????????????????????????????? void ConcreteSubject::SetState(const State& st)

????????????????????????????????????????????????????????????????????? {???? _st = st;

????????????????????????????????????????????????????????????????????? }

????????????????????????????????????????????????? 第? 70??? 頁 共? 105????? 頁???????????????????????????????????????????? k_eckel

----------------------- Page 71-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????? 代碼片斷 3:Observer.h???????????????????????????????????????????? 代碼片斷4:Observer.cpp

???? //Observer.h??????????????????????????????????????????????????? //Observer.cpp

???? #ifndef _OBSERVER_H_??????????????????????????????????????????? #include "Observer.h"

???? #define _OBSERVER_H_??????????????????????????????????????????? #include "Subject.h"

???? #include "Subject.h"??????????????????????????????????????????? #include <iostream>

???? #include <string>?????????????????????????????????????????????? #include <string>

???? using namespace std;??????????????????????????????????????????? using namespace std;

???? typedef string State;?????????????????????????????????????????? Observer::Observer()

???? class Observer????????????????????????????????????????????????? {

???? {????????????????????????????????????????????????????????????????????? _st = '/0';

???? public:???????????????????????????????????????????????????????? }

??????????? virtual ~Observer();

?????????? virtual void Update(Subject* sub) = 0;??????????????????? Observer::~Observer()

?????????? virtual void PrintInfo() = 0;???????????????????????????? {

???? protected:????????????????????????????????????????????????????? }

??????????? Observer();????????????????????????????????????????????? ConcreteObserverA::ConcreteObserverA(Subje

??????????? State _st;?????????????????????????????????????????????? ct* sub)

???? private:??????????????????????????????????????????????????????? {

???? };??????????????????????????????????????????????????????????????????? _sub = sub;

???? class ConcreteObserverA:public Observer??????????????????????????????? _sub->Attach(this);

???? {?????????????????????????????????????????????????????????????? }

???? public:???????????????????????????????????????????????????????? ConcreteObserverA::~ConcreteObserverA()

??????????? virtual Subject* GetSubject();?????????????????????????? {

??????????? ConcreteObserverA(Subject* sub);??????????????????????????????? _sub->Detach(this);

??????????? virtual ~ConcreteObserverA();????????????????????????????????? if (_sub != 0)

???? //傳入 Subject?????? 作為參數,這樣可以讓一個????????????????????????????????????????????? delete _sub;

???? View 屬于多個的 Subject。???????????????????????????????????????????? }

?????????? void??? Update(Subject* sub);???????????????????????????? Subject* ConcreteObserverA::GetSubject()

??????????? void PrintInfo();??????????????????????????????????????? {

???? protected:???????????????????????????????????????????????????????????? return _sub;

???? private:??????????????????????????????????????????????????????? }

??????????? Subject* _sub;?????????????????????????????????????????? void ConcreteObserverA::PrintInfo()

???? };????????????????????????????????????????????????????????????? {

???? class ConcreteObserverB:public Observer??????????????????????????????? cout<<"ConcreteObserverA?????????? observer....

???? {?????????????????????????????????????????????????????????????? "<<_sub->GetState()<<endl;

???? public:???????????????????????????????????????????????????????? }

??????????? virtual Subject* GetSubject();?????????????????????????? void ConcreteObserverA::Update(Subject* sub)

??????????? ConcreteObserverB(Subject* sub);???????????????????????? {

??????????? virtual ~ConcreteObserverB();????????????????????????????????? _st = sub->GetState();

???? //傳入 Subject?????? 作為參數,這樣可以讓一個??????????????????????????????????????? PrintInfo();

???? View 屬于多個的 Subject。???????????????????????????????????????????? }

?????????? void??? Update(Subject* sub);???????????????????????????? ConcreteObserverB::ConcreteObserverB(Subje

??????????? void PrintInfo();??????????????????????????????????????? ct* sub)

???? protected:????????????????????????????????????????????????????? {

???? private:????????????????????????????????????????????????????????????? _sub = sub;

??????????? Subject* _sub;????????????????????????????????????????????????? _sub->Attach(this);
???????????????????????????????????????????????? 第? 71??? 頁 共? 105????? 頁??????????????????????????????????????????? k_eckel
???? };????????????????????????????????????????????????????????????? }

???? #endif //~_OBSERVER_H_

----------------------- Page 72-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 5:main.cpp???????????????????????????????????????? 代碼片斷4:Observer.cpp

? //main.cpp??????????????????????????????????????????????? ConcreteObserverB::~ConcreteObserverB()

???????????????????????????????????????????????????????????? {

? #include "Subject.h"??????????????????????????????????????????? _sub->Detach(this);

? #include "Observer.h"?????????????????????????????????????????? if (_sub != 0)

?????????????????????????????????????????????????????????????????? {

? #include <iostream>????????????????????????????????????????????????? delete _sub;

? using namespace std;???????????????????????????????????????????? }

???????????????????????????????????????????????????????????? Subject* ConcreteObserverB::GetSubject()

? int main(int argc,char* argv[])??????????????????????????? {

? {??????????????????????????????????????????????????????????????? return _sub;

?????? ConcreteSubject*?????? sub???? =???? new????????????? }

? ConcreteSubject();??????????????????????????????????????? void ConcreteObserverB::PrintInfo()

?????? Observer*????????? o1?????? =??????? new????????????? {

? ConcreteObserverA(sub);?????????????????????????????????? cout<<"ConcreteObserverB??????????? observer....

?????? Observer*????????? o2?????? =??????? new????????????? "<<_sub->GetState()<<endl;

? ConcreteObserverB(sub);??????????????????????????????????? }

??????? sub->SetState("old");?????????????????????????????? void ConcreteObserverB::Update(Subject* sub)

??????? sub->Notify();?????????????????????????????????????? {

??????? sub->SetState("new");? // 也 可 以 由???????????????????????? _st = sub->GetState();

? Observer 調用????????????????????????????????????????????????????? PrintInfo();

??????? sub->Notify();?????????????????????????????????????? }

??????? return 0;

? }

?代碼說明

???? 在Observer 模式的實現中,Subject 維護一個list 作為存儲其所有觀察者的容器。每當

調用Notify 操作就遍歷list 中的Observer 對象,并廣播通知改變狀態(調用Observer 的Update

操作)。目標的狀態state 可以由 Subject? 自己改變(示例),也可以由Observer 的某個操作引

起 state 的改變(可調用 Subject 的SetState 操作)。Notify 操作可以由 Subject? 目標主動廣播

?(示例),也可以由Observer 觀察者來調用(因為Observer 維護一個指向 Subject 的指針)。

???? 運行示例程序,可以看到當 Subject 處于狀態 “old”時候,依賴于它的兩個觀察者都顯

示“old”,當目標狀態改變為“new ”的時候,依賴于它的兩個觀察者也都改變為“new ”。

?討論

????? Observer 是影響極為深遠的模式之一,也是在大型系統開發過程中要用到的模式之一。

除了MFC、Struts 提供了MVC 的實現框架,在Java 語言中還提供了專門的接口實現Observer

模式:通過專門的類 Observable 及 Observer 接口來實現MVC 編程模式,其UML? 圖可以表

????????????????????????????????????????? 第? 72? 頁 共? 105??? 頁???????????????????????????????????? k_eckel

----------------------- Page 73-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

示為:

???????????????????????? Java 中實現MVC 的UML? 圖。

這里的Observer 就是觀察者,Observable 則充當目標 Subject 的角色。

???? Observer 模式也稱為發布-訂閱(publish-subscribe),目標就是通知的發布者,觀察者

則是通知的訂閱者(接受通知)。

3.5 Memento 模式

?問題

??? 沒有人想犯錯誤,但是沒有人能夠不犯錯誤。犯了錯誤一般只能改過,卻很難改正 (恢

復)。世界上沒有后悔藥,但是我們在進行軟件系統的設計時候是要給用戶后悔的權利(實

際上可能也是用戶要求的權利:)),我們對一些關鍵性的操作肯定需要提供諸如撤銷(Undo )

的操作。那這個后悔藥就是Memento 模式提供的。

?模式選擇

???????? Memento 模式的關鍵就是要在不破壞封裝行的前提下,捕獲并保存一個類的內部

狀態,這樣就可以利用該保存的狀態實施恢復操作。為了達到這個目標,可以在后面的實現

中看到我們采取了一定語言支持的技術。Memento 模式的典型結構圖為:

????????????????????????????? 第? 73 頁 共? 105 頁??????????????????????? k_eckel

----------------------- Page 74-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????????????????????????? 圖2-1:Memento Pattern 結構圖

?實現

?完整代碼示例(code)

?????? Memento???? 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

??????????????? 代碼片斷 1:Memento.h??????????????????????????????????????? 代碼片斷2:Memento.cpp

???? //Memento.h????????????????????????????????????????????? //Memento.cpp

???? #ifndef _MEMENTO_H_????????????????????????????????????? #include "Memento.h"

???? #define _MEMENTO_H_????????????????????????????????????? #include <iostream>

???? #include <string>??????????????????????????????????????? using namespace std;

???? using namespace std;???????????????????????????????????? typedef string State;

???? class Memento;?????????????????????????????????????????? Originator::Originator()

???? class Originator????????????????????????????????????????? {

???? {????????????????????????????????????????????????????????????? _sdt = "";

???? public:??????????????????????????????????????????????????????? _mt = 0;

????????? typedef string State;??????????????????????????????? }

?????????? Originator();????????????????????????????????????? Originator::Originator(const State& sdt)

????????? Originator(const State& sdt);??????????????????????? {

?????????? ~Originator();?????????????????????????????????????????? _sdt = sdt;

?????????? Memento* CreateMemento();??????????????????????????????? _mt = 0;

????????? void SetMemento(Memento* men);?????????????????????? }

????????? void RestoreToMemento(Memento* mt);???????????????? Originator::~Originator()

?????????? State GetState();?????????????????????????????????? {

????????? void SetState(const State& sdt);???????????????????? }

?????????? void PrintState();???????????????????????????????? Memento* Originator::CreateMemento()

???? protected:??????????????????????????????????????????????? {

???? private:?????????????????????????????????????????????????????? return new Memento(_sdt);

?????????? State _sdt;???????????????????????????????????????? }

?????????? Memento* _mt;

???? };

???????????????????????????????????????????? 第? 74? 頁 共? 105???? 頁??????????????????????????????????????? k_eckel

----------------------- Page 75-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????? 代碼片斷 1:Memento.h????????????????????????????????????????? 代碼片斷2:Memento.cpp

???? class Memento??????????????????????????????????????????????? State Originator::GetState()

???? {??????????????????????????????????????????????????????????? {

???? public:???????????????????????????????????????????????????????????? return _sdt;

???? protected:?????????????????????????????????????????????????? }

???? private:??????????????????????????????????????????????????? void Originator::SetState(const State& sdt)

??????????? //這是最關鍵的地方,將 Originator????????????????? 為??????????? {

???? friend 類,可以訪問內部信息,但是其他類不?????????????????????????????????????????? _sdt = sdt;

???? 能訪問????????????????????????????????????????????????????????? }

??????????? friend class Originator;???????????????????????????? void Originator::PrintState()

?????????? typedef string State;????????????????????????????????? {

??????????? Memento();?????????????????????????????????????????????????? cout<<this->_sdt<<"....."<<endl;

??????????? Memento(const State& sdt);??????????????????????????? }

??????????? ~Memento();????????????????????????????????????????? void Originator::SetMemento(Memento* men)

?????????? void SetState(const State& sdt);?????????????????????? {

??????????? State GetState();???????????????????????????????????? }

???? private:??????????????????????????????????????????????????? void

??????????? State _sdt;????????????????????????????????????????? Originator::RestoreToMemento(Memento* mt)

???? };?????????????????????????????????????????????????????????? {

???? #endif //~_MEMENTO_H_?????????????????????????????????????????????? this->_sdt = mt->GetState();

????????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????? //class Memento

????????????????? 代碼片斷 3:main.cpp??????????????????????????????? Memento::Memento()

???? //main.cpp?????????????????????????????????????????????????? {

???? #include "Memento.h"???????????????????????????????????????? }

???? #include <iostream>???????????????????????????????????????? Memento::Memento(const State& sdt)

???? using namespace std;???????????????????????????????????????? {

???? int main(int argc,char* argv[])??????????????????????????????????? _sdt = sdt;

???? {??????????????????????????????????????????????????????????? }

?????????? Originator* o = new Originator();????????????????????? State Memento::GetState()

??????????? o->SetState("old"); //備忘前狀態?????????????????????????? {

??????????? o->PrintState();???????????????????????????????????????????? return _sdt;

?????????? Memento*?? m?? =?? o->CreateMemento();? //???????????? }

???? 將狀態備忘?????????????????????????????????????????????????????? void Memento::SetState(const State& sdt)

??????????? o->SetState("new"); //修改狀態??????????????????????????? {

??????????? o->PrintState();??????????????????????????????????????????? _sdt = sdt;

?????????? o->RestoreToMemento(m);???????????????????? //???????? }

???? 恢復修改前狀態

??????????? o->PrintState();

??????????? return 0;

???? }

?????????????????????????????????????????????? 第? 75?? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 76-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?代碼說明

???? Memento 模式的關鍵就是friend class Originator;我們可以看到,Memento 的接口都聲明

為 private,而將 Originator? 聲明為 Memento??? 的友元類。我們將 Originator?????? 的狀態保存在

Memento 類中,而將Memento 接口private 起來,也就達到了封裝的功效。

??? 在 Originator 類中我們提供了方法讓用戶后悔:RestoreToMemento(Memento*?????????? mt);我們可以

通過這個接口讓用戶后悔。在測試程序中,我們演示了這一點:Originator 的狀態由old 變為 new 最

后又回到了old。

?討論

??? 在Command 模式中,Memento 模式經常被用來維護可以撤銷 (Undo )操作的狀態。這

一點將在Command 模式具體說明。

3.6 Mediator 模式

?問題

??? 在面向對象系統的設計和開發過程中,對象之間的交互和通信是最為常見的情況,因為

對象間的交互本身就是一種通信。在系統比較小的時候,可能對象間的通信不是很多、對象

也比較少,我們可以直接硬編碼到各個對象的方法中。但是當系統規模變大,對象的量變引

起系統復雜度的急劇增加,對象間的通信也變得越來越復雜,這時候我們就要提供一個專門

處理對象間交互和通信的類,這個中介者就是 Mediator? 模式。Mediator? 模式提供將對象間

的交互和通訊封裝在一個類中,各個對象間的通信不必顯勢去聲明和引用,大大降低了系統

的復雜性能 (了解一個對象總比深入熟悉n 個對象要好)。另外Mediator 模式還帶來了系統

對象間的松耦合,這些將在討論中詳細給出。

?模式選擇

???? Mediator 模式典型的結構圖為:

????????????????????????????? 第? 76 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 77-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????????????? 圖2-1:Mediator Pattern 結構圖

??? Mediator 模式中,每個 Colleague????? 維護一個 Mediator ,當要進行交互,例如圖中

ConcreteColleagueA 和 ConcreteColleagueB 之間的交互就可以通過 ConcreteMediator 提供的

DoActionFromAtoB 來處理,ConcreteColleagueA 和ConcreteColleagueB 不必維護對各自的引

用,甚至它們也不知道各個的存在。Mediator???????????????? 通過這種方式將多對多的通信簡化為了一

?(Mediator)對多(Colleague)的通信。

?實現

?完整代碼示例(code)

???? Mediator 模式實現不是很困難,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 77 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 78-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 1:Colleage.h???????????????????????????????????????????? 代碼片斷2:Colleage.cpp

? #ifndef _COLLEAGE_H_?????????????????????????????????????????? //Colleage.cpp

? #define _COLLEAGE_H_?????????????????????????????????????????? #include "Mediator.h"

? #include <string>????????????????????????????????????????????? #include "Colleage.h"

? using namespace std;?????????????????????????????????????????? #include <iostream>

? class Mediator;??????????????????????????????????????????????? using namespace std;

? class Colleage???????????????????????????????????????????????? Colleage::Colleage()

? {?????????????????????????????????????????????????????????????? {??? }

? public:??????????????????????????????????????????????????????? Colleage::Colleage(Mediator* mdt)

???????? virtual ~Colleage();???????????????????????????????????? {??? this->_mdt = mdt; }

??????? virtual void Aciton() = 0;?????????????????????????????? Colleage::~Colleage()

? virtual void SetState(const string& sdt) = 0;?????????????????? {???? }

??????? virtual string GetState() = 0;?????????????????????????? ConcreteColleageA::ConcreteColleageA()

? protected:????????????????????????????????????????????????????? {???? }

???????? Colleage();???????????????????????????????????????????? ConcreteColleageA::~ConcreteColleageA()

???????? Colleage(Mediator* mdt);???????????????????????????????? {??? }

???????? Mediator* _mdt;???????????????????????????????????????? ConcreteColleageA::ConcreteColleageA(Media

? private:?????????????????????????????????????????????????????? tor* mdt):Colleage(mdt)????? {??? }

? };???????????????????????????????????????????????????????????? string ConcreteColleageA::GetState()

? class ConcreteColleageA:public Colleage???????????????????????? {??? return_sdt;?? }

? {????????????????????????????????????????????????????????????? void?????????? ConcreteColleageA::SetState(const

? public:??????????????????????????????????????????????????????? string& sdt)

???????? ConcreteColleageA();???????????????????????????????????? {??? _sdt = sdt;

???????? ConcreteColleageA(Mediator* mdt);??????????????????????? }

???????? ~ConcreteColleageA();?????????????????????????????????? void ConcreteColleageA::Aciton()

???????? void Aciton();?????????????????????????????????????????? {

??????? void SetState(const string& sdt);??????????????????????????????? _mdt->DoActionFromAtoB();

???????? string GetState();???????????????????????????????????????????? cout<<"State?? of?? ConcreteColleageB:"<<"

? protected:????????????????????????????????????????????????????? "<<this->GetState()<<endl;

? private:??????????????????????????????????????????????????????? }

???????? string _sdt;??????????????????????????????????????????? ConcreteColleageB::ConcreteColleageB()

? };????????????????????????????????????????????????????????????? {??? }

? class ConcreteColleageB:public Colleage??????????????????????? ConcreteColleageB::~ConcreteColleageB()

? {?????????????????????????????????????????????????????????????? {??? }

? public:??????????????????????????????????????????????????????? ConcreteColleageB::ConcreteColleageB(Media

???????? ConcreteColleageB();??????????????????????????????????? tor* mdt):Colleage(mdt)

???????? ConcreteColleageB(Mediator* mdt);??????????????????????? {???? }

???????? ~ConcreteColleageB();?????????????????????????????????? void ConcreteColleageB::Aciton()

???????? void Aciton();?????????????????????????????????????????? {_mdt->DoActionFromBtoA();

??????? void SetState(const string& sdt);??????????????????????? cout<<"State?????? of???? ConcreteColleageB:"<<"

???????? string GetState();?????????????????????????????????????? "<<this->GetState()<<endl;

? protected:????????????????????????????????????????????????????? }

? private:?????????????????????????????????????????????????????? string ConcreteColleageB::GetState()

???????? string _sdt;???????????????????????????????????????????? {?? return_sdt; }

? };???????????????????????????????????????????????????????????? void?????????? ConcreteColleageB::SetState(const
?????????????????????????????????????????????? 第? 78?? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel
? #endif //~_COLLEAGE_H_???????????????????????????????????????? string& sdt)

????????????????????????????????????????????????????????????????? {??? _sdt = sdt;??? }

----------------------- Page 79-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????? 代碼片斷 3:Mediator.h?????????????????????????????????????????????? 代碼片斷4:Mediator.cpp

???? //Mediator.h??????????????????????????????????????????????????? //Mediator.cpp

???? #ifndef _MEDIATOR_H_??????????????????????????????????????????? #include "Mediator.h"

???? #define _MEDIATOR_H_??????????????????????????????????????????? #include "Colleage.h"

???? class Colleage;???????????????????????????????????????????????? Mediator::Mediator()

????????????????????????????????????????????????????????????????????? {????? }

???? class Mediator????????????????????????????????????????????????? Mediator::~Mediator()

???? {??????????????????????????????????????????????????????????????? {????? }

???? public:???????????????????????????????????????????????????????? ConcreteMediator::ConcreteMediator()

??????????? virtual ~Mediator();????????????????????????????????????? {????? }

?????????? virtual void DoActionFromAtoB() = 0;????????????????????? ConcreteMediator::~ConcreteMediator()

?????????? virtual void DoActionFromBtoA() = 0;?????????????????????? {????? }

???? protected:????????????????????????????????????????????????????? ConcreteMediator::ConcreteMediator(Colleage

??????????? Mediator();????????????????????????????????????????????? * clgA,Colleage* clgB)

???? private:???????????????????????????????????????????????????????? {??? this->_clgA = clgA;

???? };??????????????????????????????????????????????????????????????????? this->_clgB = clgB;

???? class ConcreteMediator:public Mediator????????????????????????? }

???? {?????????????????????????????????????????????????????????????? void ConcreteMediator::DoActionFromAtoB()

???? public:????????????????????????????????????????????????????????? { _clgB->SetState(_clgA->GetState()); }

??????????? ConcreteMediator();????????????????????????????????????? void

??????????? ConcreteMediator(Colleage*?????????????????????????????? ConcreteMediator::SetConcreteColleageA(Coll

???? clgA,Colleage* clgB);?????????????????????????????????????????? eage* clgA)

??????????? ~ConcreteMediator();????????????????????????????????????? {??? this->_clgA = clgA;???? }

??????????? void?? SetConcreteColleageA(Colleage*??????????????????? void

???? clgA);????????????????????????????????????????????????????????? ConcreteMediator::SetConcreteColleageB(Coll

??????????? void??? SetConcreteColleageB(Colleage*?????????????????? eage* clgB)

???? clgB);?????????????????????????????????????????????????????????? {? this->_clgB = clgB;???? }

??????????? Colleage* GetConcreteColleageA();??????????????????????? Colleage*

??????????? Colleage* GetConcreteColleageB();??????????????????????? ConcreteMediator::GetConcreteColleageA()

??????????? void???????????? IntroColleage(Colleage*????????????????? {? return_clgA;??? }

???? clgA,Colleage* clgB);?????????????????????????????????????????? Colleage*

??????????? void DoActionFromAtoB();???????????????????????????????? ConcreteMediator::GetConcreteColleageB()

??????????? void DoActionFromBtoA();????????????????????????????????? {? return_clgB;??? }

???? protected:????????????????????????????????????????????????????? void

???? private:??????????????????????????????????????????????????????? ConcreteMediator::IntroColleage(Colleage*

??????????? Colleage* _clgA;???????????????????????????????????????? clgA,Colleage* clgB)

????????????????????????????????????????????????????????????????????? {??? this->_clgA = clgA;

??????????? Colleage* _clgB;?????????????????????????????????????????????? this->_clgB = clgB;

???????????????????????????????????????????????????????????????????? }

???? };????????????????????????????????????????????????????????????? void ConcreteMediator::DoActionFromBtoA()

???? #endif //~_MEDIATOR_H??????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????????? _clgA->SetState(_clgB->GetState());

???????????????????????????????????????????????????????????????????? }

????????????????????????????????????????????? 第? 79? 頁 共? 105???? 頁???????????????????????????????????????? k_eckel

----------------------- Page 80-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????????? 代碼片斷 5:main.cpp

??????? //main.cpp

??????? #include "Mediator.h"

??????? #include "Colleage.h"

??????? #include <iostream>

??????? using namespace std;

??????? int main(int argc,char* argv[])

??????? {

?????????????? ConcreteMediator*??????? m???? =?????? new

??????? ConcreteMediator();

????????????? ConcreteColleageA*???????? c1??? =????? new

??????? ConcreteColleageA(m);

????????????? ConcreteColleageB*???????? c2???? =???? new

??????? ConcreteColleageB(m);

?????????????? m->IntroColleage(c1,c2);

?????????????? c1->SetState("old");

?????????????? c2->SetState("old");

?????????????? c1->Aciton();

?????????????? c2->Aciton();

?????????????? cout<<endl;

?????????????? c1->SetState("new");

?????????????? c1->Aciton();

?????????????? c2->Aciton();

?????????????? cout<<endl;

?????????????? c2->SetState("old");

?????????????? c2->Aciton();

?????????????? c1->Aciton();

?????????????? return 0;

??????? }

?代碼說明

?????? Mediator 模式的實現關鍵就是將對象 Colleague 之間的通信封裝到一個類種單獨處理,

為了模擬Mediator 模式的功能,這里給每個 Colleague 對象一個 string 型別以記錄其狀態,

并通過狀態改變來演示對象之間的交互和通信。這里主要就 Mediator?????????????????????????????????????????????????????? 的示例運行結果給出

分析:

?????? 1 )將ConcreteColleageA 對象設置狀態“old”,ConcreteColleageB 也設置狀態“old”;

?????? 2 )ConcreteColleageA??? 對象改變狀態,并在 Action???????????????? 中和 ConcreteColleageB?????? 對象進行通信,并改變

???????????????????????????????????????????? 第? 80?? 頁 共? 105??? 頁???????????????????????????????????????? k_eckel

----------------------- Page 81-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

ConcreteColleageB 對象的狀態為“new ”;

???? 3 )ConcreteColleageB 對象改變狀態,并在 Action 中和 ConcreteColleageA 對象進行通信,并改變

ConcreteColleageA 對象的狀態為“new ”;

??? 注意到,兩個 Colleague? 對象并不知道它交互的對象,并且也不是顯示地處理交互過程,這一切都是

通過Mediator 對象完成的,示例程序運行的結果也正是證明了這一點。

?討論

???? Mediator 模式是一種很有用并且很常用的模式,它通過將對象間的通信封裝到一個類

中,將多對多的通信轉化為一對多的通信,降低了系統的復雜性。Mediator 還獲得系統解耦

的特性,通過Mediator,各個Colleague 就不必維護各自通信的對象和通信協議,降低了系

統的耦合性,Mediator 和各個Colleague 就可以相互獨立地修改了。

???? Mediator 模式還有一個很顯著額特點就是將控制集中,集中的優點就是便于管理,也正

式符合了OO 設計中的每個類的職責要單一和集中的原則。

3.7 Command 模式

?問題

???? Command 模式通過將請求封裝到一個對象 (Command)中,并將請求的接受者存放到

具體的ConcreteCommand 類中 (Receiver)中,從而實現調用操作的對象和操作的具體實現

者之間的解耦。

?模式選擇

??? Command 模式的典型結構圖為:

????????????????????????????? 第? 81 頁 共? 105 頁????????????????????????? k_eckel

----------------------- Page 82-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????????????????????? 圖2-1:Command Pattern 結構圖

????? Command???? 模式結構圖中,將請求的接收者(處理者)放到 Command???????????????????????????????????????????? 的具體子類

ConcreteCommand?????? 中,當請求到來時 (Invoker???????????????? 發出 Invoke?????? 消息激活 Command??????????? 對象),

ConcreteCommand 將處理請求交給Receiver 對象進行處理。

?實現

?完整代碼示例(code)

????? Command? 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

?????????????? 代碼片斷 1:Reciever.h?????????????????????????????????? 代碼片斷2:Reciever.cpp

??? //Reciever.h???????????????????????????????????????? //Reciever.cpp

??? #ifndef _RECIEVER_H_

??? #define _RECIEVER_H_???????????????????????????????? #include "Reciever.h"

??? class Reciever

??? {??????????????????????????????????????????????????? #include <iostream>

??? public:

????????? Reciever();??????????????????????????????????? Reciever::Reciever()

????????? ~Reciever();?????????????????????????????????? {

????????? void Action();

??? protected:?????????????????????????????????????????? }

??? private:

??? };?????????????????????????????????????????????????? Reciever::~Reciever()

??? #endif //~_RECIEVER_H_?????????????????????????????? {

???????????????????????????????????????????????????????? }

???????????????????????????????????????????????????????? void Reciever::Action()

???????????????????????????????????????????????????????? {

???????????????????????????????????????? 第? 82? 頁 共? 105?? 頁 std::cout<<"Reciever??????????????? k_eckel

???????????????????????????????????????????????????????? action......."<<std::endl;

???????????????????????????????????????????????????????? }

----------------------- Page 83-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????? 代碼片斷 3:Command.h?????????????????????????????????????????????? 代碼片斷4:Command.cpp

? //Command.h?????????????????????????????????????????????????????? //Composite.cpp

??????????????????????????????????????????????????????????????????? #include "Composite.h"

? #ifndef _COMMAND_H_?????????????????????????????????????????????? #include "Component.h"

? #define _COMMAND_H_?????????????????????????????????????????????? #define NULL 0??????? //define NULL POINTOR

??????????????????????????????????????????????????????????????????? Composite::Composite()

? class Reciever;?????????????????????????????????????????????????? {

????????????????????????????????????????????????????????????????????????? //vector<Component*>::iterator???????? itend?? =

? class Command???????????????????????????????????????????????????? comVec.begin();

?? {??????????????????????????????????????????????????????????????? }

? public:?????????????????????????????????????????????????????????? Composite::~Composite()

????????? virtual ~Command();?????????????????????????????????????? {

??????????????????????????????????????????????????????????????????? }

???????? virtual void Excute() = 0;???????????????????????????????? void Composite::Operation()

??????????????????????????????????????????????????????????????????? {

? protected:?????????????????????????????????????????????????????????????? vector<Component*>::iterator?????? comIter?? =

????????? Command();??????????????????????????????????????????????? comVec.begin();

? private:???????????????????????????????????????????????????????????????? for (;comIter != comVec.end();comIter++)

?????????????????????????????????????????????????????????????????????????? {

? };???????????????????????????????????????????????????????????????????????????? (*comIter)->Operation();

?????????????????????????????????????????????????????????????????????????? }

? class ConcreteCommand:public Command????????????????????????????? }

?? {??????????????????????????????????????????????????????????????? void Composite::Add(Component* com)

? public:?????????????????????????????????????????????????????????? {

????????? ConcreteCommand(Reciever* rev);????????????????????????????????? comVec.push_back(com);

??????????????????????????????????????????????????????????????????? }

????????? ~ConcreteCommand();?????????????????????????????????????? void Composite::Remove(Component* com)

??????????????????????????????????????????????????????????????????? {

????????? void Excute();?????????????????????????????????????????????????? comVec.erase(&com);

??????????????????????????????????????????????????????????????????? }

? protected:??????????????????????????????????????????????????????? Component* Composite::GetChild(int index)

??????????????????????????????????????????????????????????????????? {

? private:???????????????????????????????????????????????????????????????? return comVec[index];

????????? Reciever* _rev;?????????????????????????????????????????? }

? };

? #endif //~_COMMAND_H_

???????????????????????????????????????????????? 第? 83?? 頁 共? 105????? 頁??????????????????????????????????????????? k_eckel

----------------------- Page 84-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 5:Invoker.h??????????????????????????????????????????????????? 代碼片斷 6:Invoker.cpp

? //Invoker.h????????????????????????????????????????????????????????? //Leaf.cpp

? #ifndef _INVOKER_H_????????????????????????????????????????????????? #include "Leaf.h"

? #define _INVOKER_H_????????????????????????????????????????????????? #include <iostream>

?????????????????????????????????????????????????????????????????????? using namespace std;

? class Command;

?????????????????????????????????????????????????????????????????????? Leaf::Leaf()

? class Invoker???????????????????????????????????????????????????????? {

? {

? public:????????????????????????????????????????????????????????????? }

???????? Invoker(Command* cmd);

?????????????????????????????????????????????????????????????????????? Leaf::~Leaf()

???????? ~Invoker();??????????????????????????????????????????????????? {

???????? void Invoke();??????????????????????????????????????????????? }

? protected:?????????????????????????????????????????????????????????? void Leaf::Operation()

??????????????????????????????????????????????????????????????????????? {

? private:??????????????????????????????????????????????????????????????????? cout<<"Leaf operation....."<<endl;

???????? Command* _cmd;??????????????????????????????????????????????? }

? };

? #endif //~_INVOKER_H_

?????????????? 代碼片斷7:main.cpp

? //main.cpp

? #include "Command.h"

? #include "Invoker.h"

? #include "Reciever.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

??????? Reciever* rev = new Reciever();

??????? Command*???????????? cmd???????? =??????? new

? ConcreteCommand(rev);

??????? Invoker* inv = new Invoker(cmd);

???????? inv->Invoke();

???????? return 0;

? }

?????????????????????????????????????????????? 第? 84??? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 85-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?代碼說明

????? Command? 模式在實現的實現和思想都很簡單,其關鍵就是將一個請求封裝到一個類中

?(Command),再提供處理對象 (Receiver ),最后Command 命令由Invoker 激活。另外,我

們可以將請求接收者的處理抽象出來作為參數傳給Command 對象,實際也就是回調的機制

?(Callback)來實現這一點,也就是說將處理操作方法地址(在對象內部)通過參數傳遞給

Command 對象,Command 對象在適當的時候 (Invoke 激活的時候)再調用該函數。這里就

要用到C++中的類成員函數指針的概念,為了方便學習,這里給出一個簡單的實現源代碼供

參考:

??????????? 代碼片斷 1:Reciever.h?????????????????????????????????? 代碼片斷2:Reciever.cpp

? //Reciever.h??????????????????????????????????????? //Reciever.cpp

? #ifndef _RECIEVER_H_??????????????????????????????? #include "Reciever.h"

? #define _RECIEVER_H_

????????????????????????????????????????????????????? #include <iostream>

? class Reciever

? {?????????????????????????????????????????????????? Reciever::Reciever()

? public:???????????????????????????????????????????? {

??????? Reciever();

????????????????????????????????????????????????????? }

??????? ~Reciever();

????????????????????????????????????????????????????? Reciever::~Reciever()

??????? void Action();??????????????????????????????? {

? protected:????????????????????????????????????????? }

? private:??????????????????????????????????????????? void Reciever::Action()

????????????????????????????????????????????????????? {

? };??????????????????????????????????????????????????????? std::cout<<"Reciever

????????????????????????????????????????????????????? action......."<<std::endl;

????????????????????????????????????????????????????? }

? #endif //~_RECIEVER_H_

???????????????????????????????????????? 第? 85 頁 共? 105??? 頁??????????????????????????????????? k_eckel

----------------------- Page 86-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 3:Command.h????????????????????????????????????????? 代碼片斷4:main.cpp

? template <class Reciever>???????????????????????????????? //main.cpp

? class SimpleCommand:public Command??????????????????????? #include "Command.h"

? {???????????????????????????????????????????????????????? #include "Reciever.h"

? public:?????????????????????????????????????????????????? #include <iostream>

??????? typedef void (Reciever::* Action)();??????????????? using namespace std;

? SimpleCommand(Reciever* rev,Action act)?????????????????? int main(int arc,char* argv[])

???????? {?????????????????????????????????????????????????? {

???????????? _rev = rev;????????????????????????????????????????? Reciever* rev = new Reciever();

???????????? _act = act;????????????????????????????????????????? Command*?????????? cmd??????? =?????? new

???????? }?????????????????????????????????????????????????? SimpleCommand<Reciever>(rev,&Reciever::A

??????? virtual void Excute()?????????????????????????????? ction);

???????? {???????????????????????????????????????????????????????? cmd->Excute();

???????????? (_rev->* _act)();???????????????????????????????????? return 0;

???????? }?????????????????????????????????????????????????? }

???????? ~SimpleCommand()

???????? {

???????????? delete _rev;

???????? }

? protected:

? private:

???????? Reciever* _rev;

???????? Action _act;

? };

? #endif //~_COMMAND_H_

????? 注意到上面通過模板的方式來參數化請求的接收者,當然是為了簡單演示。在復雜的情

況下我們會提供一個抽象Command 對象,然后創建Command 的子類以支持更復雜的處理。

?討論

?????? Command? 模式的思想非常簡單,但是 Command? 模式也十分常見,并且威力不小。實

際上,Command 模式關鍵就是提供一個抽象的Command 類,并將執行操作封裝到Command

類接口中,Command? 類中一般就是只是一些接口的集合,并不包含任何的數據屬性(當然

在示例代碼中,我們的Command 類有一個處理操作的Receiver 類的引用,但是其作用也僅

僅就是為了實現這個 Command 的Excute 接口)。這種方式在是純正的面向對象設計者最為

鄙視的設計方式,就像OO 設計新手做系統設計的時候,僅僅將Class 作為一個關鍵字,將

C 種的全局函數找一個類封裝起來就以為是完成了面向對象的設計。

????? 但是世界上的事情不是絕對的,上面提到的方式在OO 設計種絕大部分的時候可能是一

??????????????????????????????????????????? 第? 86? 頁 共? 105??? 頁?????????????????????????????????????? k_eckel

----------------------- Page 87-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

個不成熟的體現,但是在Command 模式中卻是起到了很好的效果。主要體現在:

??? 1)Command??? 模式將調用操作的對象和知道如何實現該操作的對象解耦。在上面

?????? Command 的結構圖中,Invoker 對象根本就不知道具體的是那個對象在處理Excute

?????? 操作(當然要知道是 Command 類別的對象,也僅此而已)。

??? 2 )在 Command??? 要增加新的處理操作對象很容易,我們可以通過創建新的繼承 自

?????? Command 的子類來實現這一點。

??? 3)Command 模式可以和Memento 模式結合起來,支持取消的操作。

3.8 Visitor 模式

?問題

??? 在面向對象系統的開發和設計過程,經常會遇到一種情況就是需求變更(Requirement

Changing),經常我們做好的一個設計、實現了一個系統原型,咱們的客戶又會有了新的需

求。我們又因此不得不去修改已有的設計,最常見就是解決方案就是給已經設計、實現好的

類添加新的方法去實現客戶新的需求,這樣就陷入了設計變更的夢魘:不停地打補丁,其帶

來的后果就是設計根本就不可能封閉、編譯永遠都是整個系統代碼。

???? Visitor 模式則提供了一種解決方案:將更新(變更)封裝到一個類中(訪問操作),并

由待更改類提供一個接收接口,則可達到效果。

?模式選擇

??? 我們通過Visitor 模式解決上面的問題,其典型的結構圖為:

????????????????????????????? 第? 87 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 88-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????????????????? 圖2-1:Visitor Pattern 結構圖

???? Visitor 模式在不破壞類的前提下,為類提供增加新的新操作。Visitor 模式的關鍵是雙分

派(Double-Dispatch )的技術 【注釋1】。C++語言支持的是單分派。

??? 在 Visitor 模式中 Accept? ()操作是一個雙分派的操作。具體調用哪一個具體的Accept

?()操作,有兩個決定因素:1)Element???????????? 的類型。因為 Accept????? ()是多態的操作,需要具

體的 Element 類型的子類才可以決定到底調用哪一個 Accept???????????????? ()實現;2)Visitor 的類型。

Accept ()操作有一個參數(Visitor*?? vis),要決定了實際傳進來的Visitor? 的實際類別才可

以決定具體是調用哪個VisitConcrete???????? ()實現。

?實現

?完整代碼示例(code)

???? Visitor 模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代碼

?(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

?【注釋1】:雙分派意味著執行的操作將取決于請求的種類和接收者的類型。更多資料請參

????????? 考資料。

????????????????????????????? 第? 88 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 89-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????? 代碼片斷 1:Visitor.h???????????????????????????????????????????????? 代碼片斷 3:Template.cpp

? //Visitor.h??????????????????????????????????????????????????????? //Element.h

? #ifndef _VISITOR_H_??????????????????????????????????????????????? #ifndef _ELEMENT_H_

? #define _VISITOR_H_??????????????????????????????????????????????? #define _ELEMENT_H_

? class ConcreteElementA;??????????????????????????????????????????? class Visitor;

? class ConcreteElementB;??????????????????????????????????????????? class Element

? class Element;????????????????????????????????????????????????????? {

? class Visitor????????????????????????????????????????????????????? public:

?? {???????????????????????????????????????????????????????????????????????? virtual ~Element();

? public:?????????????????????????????????????????????????????????????????? virtual void Accept(Visitor* vis) = 0;

????????? virtual ~Visitor();??????????????????????????????????????? protected:

???????? virtual void??????????????????????????????????????????????????????? Element();

? VisitConcreteElementA(Element* elm) = 0;?????????????????????????? private:

????????? virtual void?????????????????????????????????????????????? };

? VisitConcreteElementB(Element* elm) = 0;?????????????????????????? class ConcreteElementA:public Element

? protected:????????????????????????????????????????????????????????? {

????????? Visitor();???????????????????????????????????????????????? public:

? private:?????????????????????????????????????????????????????????????????? ConcreteElementA();

? };???????????????????????????????????????????????????????????????????????? ~ConcreteElementA();

? class ConcreteVisitorA:public Visitor????????????????????????????????????? void Accept(Visitor* vis);

?? {???????????????????????????????????????????????????????????????? protected:

? public:??????????????????????????????????????????????????????????? private:

????????? ConcreteVisitorA();??????????????????????????????????????? };

????????? virtual ~ConcreteVisitorA();?????????????????????????????? class ConcreteElementB:public Element

????????? virtual void??????????????????????????????????????????????? {

? VisitConcreteElementA(Element* elm);?????????????????????????????? public:

????????? virtual void?????????????????????????????????????????????????????? ConcreteElementB();

? VisitConcreteElementB(Element* elm);?????????????????????????????????????? ~ConcreteElementB();

? protected:???????????????????????????????????????????????????????????????? void Accept(Visitor* vis);

? private:?????????????????????????????????????????????????????????? protected:

? };???????????????????????????????????????????????????????????????? private:

? class ConcreteVisitorB:public Visitor????????????????????????????? };

?? {???????????????????????????????????????????????????????????????? #endif //~_ELEMENT_H_

? public:

????????? ConcreteVisitorB();

????????? virtual ~ConcreteVisitorB();

????????? virtual void

? VisitConcreteElementA(Element* elm);

????????? virtual void

? VisitConcreteElementB(Element* elm);

? protected:

? private:

? };

? #endif //~_VISITOR_H_

????????????????????????????????????????????????? 第? 89?? 頁 共? 105????? 頁???????????????????????????????????????????? k_eckel

----------------------- Page 90-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

???????????????? 代碼片斷2:Visitor.cpp?????????????????????????????????????????? 代碼片斷4:Element.cpp

???? //Visitor.cpp?????????????????????????????????????????????? //Element.cpp

???? #include "Visitor.h"??????????????????????????????????????? #include "Element.h"

???? #include "Element.h"??????????????????????????????????????? #include "Visitor.h"

???? #include <iostream>???????????????????????????????????????? #include <iostream>

???? using namespace std;??????????????????????????????????????? using namespace std;

???? Visitor::Visitor()????????????????????????????????????????? Element::Element()

???? {??????????????????????????????????????????????????????????? {

???? }??????????????????????????????????????????????????????????? }

???? Visitor::~Visitor()

???? {

???? }

???? ConcreteVisitorA::ConcreteVisitorA()

???? {

???? }?????????????????????????????????????????????????????????????????????? 代碼片斷4:Element.cpp

???? ConcreteVisitorA::~ConcreteVisitorA()?????????????????????? Element::~Element()

???? {??????????????????????????????????????????????????????????? {

???? }??????????????????????????????????????????????????????????? }

???? void??????????????????????????????????????????????????????? void Element::Accept(Visitor* vis)

???? ConcreteVisitorA::VisitConcreteElementA(Ele????????????????? {

???? ment* elm)?????????????????????????????????????????????????? }

???? {?????????????????????????????????????????????????????????? ConcreteElementA::ConcreteElementA()

?????????? cout<<"i??????????????? will???????????? visit???????? {

???? ConcreteElementA..."<<endl;????????????????????????????????? }

???? }?????????????????????????????????????????????????????????? ConcreteElementA::~ConcreteElementA()

???? void???????????????????????????????????????????????????????? {

???? ConcreteVisitorA::VisitConcreteElementB(Ele????????????????? }

???? ment* elm)????????????????????????????????????????????????? void ConcreteElementA::Accept(Visitor* vis)

???? {??????????????????????????????????????????????????????????? {

?????????? cout<<"i??????????????? will??????????? visit???????????????? vis->VisitConcreteElementA(this);

???? ConcreteElementB..."<<endl;???????????????????????????????????????? cout<<"visiting

???? }?????????????????????????????????????????????????????????? ConcreteElementA..."<<endl;

???? ConcreteVisitorB::ConcreteVisitorB()???????????????????????? }

???? {?????????????????????????????????????????????????????????? ConcreteElementB::ConcreteElementB()

???? }??????????????????????????????????????????????????????????? {

???? ConcreteVisitorB::~ConcreteVisitorB()??????????????????????? }

???? {?????????????????????????????????????????????????????????? ConcreteElementB::~ConcreteElementB()

???? }??????????????????????????????????????????????????????????? {

???? void???????????????????????????????????????????????????????? }

???? ConcreteVisitorB::VisitConcreteElementA(Ele???????????????? void ConcreteElementB::Accept(Visitor* vis)

???? ment* elm)?????????????????????????????????????????????????? {

???? {?????????????????????????????????????????????????????????????????? cout<<"visiting

?????????? cout<<"i??????????????? will??????????? visit???????? ConcreteElementB..."<<endl;

???? ConcreteElementA..."<<endl;???????????????????????????????????????? vis->VisitConcreteElementB(this);

???? }??????????????????????????????????????????????????????????? }

?????????????????????????????????????????????? 第? 90?? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 91-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????? 代碼片斷2:Visitor.cpp???????????????????????? 代碼片斷 5:main.cpp

?? void??????????????????????????????????? #include "Element.h"

?? ConcreteVisitorB::VisitConcreteElementB(El #include "Visitor.h"

?? ement* elm)???????????????????????????? #include <iostream>

??? {????????????????????????????????????? using namespace std;

??????? cout<<"i will visit??????????????? int main(int argc,char* argv[])

??????????? ConcreteElementB..."<<endl;???? {

??? }?????????????????????????????????????????? Visitor* vis = new ConcreteVisitorA();

??????????????????????????????????????????????? Element*????? elm????? =????? new

?????????????????????????????????????????? ConcreteElementA();

???????????????????????????????????????????????? elm->Accept(vis);

???????????????????????????????????????????????? return 0;

??????????????????????????????????????????? }

?代碼說明

???? Visitor 模式的實現過程中有以下的地方要注意:

???? 1 )Visitor 類中的Visit?? ()操作的實現。

????? 這里我們可以向Element 類僅僅提供一個接口Visit??????????????????????? (),而在Accept????? ()實現中具

???????? 體調用哪一個Visit ()操作則通過函數重載 (overload)的方式實現:我們提供Visit

????????? ()的兩個重載版本a)Visit(ConcreteElementA* elmA ),b )Visit(ConcreteElementB*

???????? elmB )。

????? 在C++中我們還可以通過RTTI????????????????? (運行時類型識別:Runtime type identification )來

???????? 實現,即我們只提供一個Visit????????????? ()函數體,傳入的參數為Element*型別參數 ,然

???????? 后用 RTTI? 決定具體是哪一類的 ConcreteElement 參數,再決定具體要對哪個具體

???????? 類施加什么樣的具體操作。【注釋2】RTTI 給接口帶來了簡單一致性,但是付出的

???????? 代價是時間(RTTI 的實現)和代碼的Hard 編碼 (要進行強制轉換)。

?討論

??? 有時候我們需要為Element 提供更多的修改,這樣我們就可以通過為Element 提供一系

列的

???? Visitor 模式可以使得Element 在不修改自己的同時增加新的操作,但是這也帶來了至少

以下的兩個顯著問題:

???? 1)破壞了封裝性。Visitor 模式要求Visitor 可以從外部修改Element 對象的狀態,這一

??????? 般通過兩個方式來實現:a)Element 提供足夠的public 接口,使得Visitor 可以通過

????????????????????????????????? 第? 91 頁 共? 105 頁?????????????????????????????? k_eckel

----------------------- Page 92-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????? 調用這些接口達到修改Element 狀態的目的;b )Element 暴露更多的細節給Visitor,

?????? 或者讓Element 提供public 的實現給Visitor (當然也給了系統中其他的對象),或者

?????? 將Visitor 聲明為Element 的friend 類,僅將細節暴露給Visitor。但是無論那種情況,

?????? 特別是后者都將是破壞了封裝性原則 (實際上就是C++的friend 機制得到了很多的

?????? 面向對象專家的詬病)。

??? 2 )ConcreteElement 的擴展很困難:每增加一個Element 的子類,就要修改Visitor 的

?????? 接口,使得可以提供給這個新增加的子類的訪問機制。從上面我們可以看到,或者

?????? 增加一個用于處理新增類的Visit?????????? ()接口,或者重載一個處理新增類的Visit?????????????? ()操

?????? 作,或者要修改RTTI 方式實現的Visit ()實現。無論那種方式都給擴展新的Element

?????? 子類帶來了困難。

3.9 Chain of Responsibility 模式

?問題

??? 熟悉VC/MFC? 的都知道,VC 是“基于消息,事件驅動”,消息在VC 開發中起著舉足

輕重的作用。在 MFC?????????? 中,消息是通過一個向上遞交的方式進行處理,例如一個

WM_COMMAND 消息的處理流程可能為:

??? 1)???? MDI 主窗口 (CMDIFrameWnd)收到命令消息WM_COMMAND,其ID 位ID_

?????????? ×××;

??? 2 )??? MDI 主窗口將消息傳給當前活動的MDI 子窗口(CMDIChildWnd);

??? 3)???? MDI 子窗口給自己的子窗口(View )一個處理機會,將消息交給View;

??? 4 )??? View 檢查自己Message Map;

??? 5)???? 如果View 沒有發現處理該消息的程序,則將該消息傳給其對應的Document 對

?????????? 象;否則View 處理,消息流程結束。

??? 6)???? Document 檢查自己Message Map,如果沒有該消息的處理程序,則將該消息傳

?????????? 給其對象的DocumentTemplate 處理;否則自己處理,消息流程結束;

??? 7)???? 如果在6)中消息沒有得到處理,則將消息返回給View;

??? 8)???? View 再傳回給MDI 子窗口;

??? 9)???? MDI 子窗口將該消息傳給 CwinApp 對象,CwinApp 為所有無主的消息提供了

????????????????????????????? 第? 92 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 93-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????? 處理。

??? 注明:有關MFC 消息處理更加詳細信息,請參考候捷先生的《深入淺出MFC》。

??? MFC 提供了消息的處理的鏈式處理策略,處理消息的請求將沿著預先定義好的路徑依

次進行處理。消息的發送者并不知道該消息最后是由那個具體對象處理的,當然它也無須也

不想知道,但是結構是該消息被某個對象處理了,或者一直到一個終極的對象進行處理了。

??? Chain?? of Responsibility 模式描述其實就是這樣一類問題將可能處理一個請求的對象鏈

接成一個鏈,并將請求在這個鏈上傳遞,直到有對象處理該請求 (可能需要提供一個默認處

理所有請求的類,例如MFC 中的CwinApp 類)。

?模式選擇

???? Chain of Responsibility 模式典型的結構圖為:

??????????????????? 圖2-1:Chain of Responsibility Pattern 結構圖

??? Chain?? of?? Responsibility 模式中ConcreteHandler 將自己的后繼對象(向下傳遞消息的對

象)記錄在自己的后繼表中,當一個請求到來時,ConcreteHandler??????????????????? 會先檢查看自己有沒有

匹配的處理程序,如果有就自己處理,否則傳遞給它的后繼。當然這里示例程序中為了簡化,

ConcreteHandler 只是簡單的檢查看自己有沒有后繼,有的話將請求傳遞給后繼進行處理,

沒有的話就自己處理。

?實現

?完整代碼示例(code)

??? Chain of Responsibility 模式的實現比較簡單,這里為了方便初學者的學習和參考,將給

出完整的實現代碼(所有代碼采用C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 93 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 94-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼?????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????????????? 代碼片斷 1:Handle.h??????????????????????????????????????????? 代碼片斷2:Handle.cpp

?????? //Handle.h????????????????????????????????????????????????? //Handle.cpp

?????? #ifndef _HANDLE_H_????????????????????????????????????????? #include "Handle.h"

?????? #define _HANDLE_H_????????????????????????????????????????? #include <iostream>

?????? class Handle??????????????????????????????????????????????? using namespace std;

??????? {????????????????????????????????????????????????????????? Handle::Handle()

?????? public:???????????????????????????????????????????????????? {

????????????? virtual ~Handle();???????????????????????????????????????? _succ = 0;

???????????? virtual void HandleRequest() = 0;???????????????????? }

???????????? void SetSuccessor(Handle* succ);????????????????????? Handle::~Handle()

????????????? Handle* GetSuccessor();????????????????????????????? {

?????? protected:???????????????????????????????????????????????????????? delete _succ;

????????????? Handle();??????????????????????????????????????????? }

????????????? Handle(Handle* succ);??????????????????????????????? Handle::Handle(Handle* succ)

?????? private:??????????????????????????????????????????????????? {

????????????? Handle* _succ;???????????????????????????????????????????? this->_succ = succ;

?????? };????????????????????????????????????????????????????????? }

?????? class ConcreteHandleA:public Handle???????????????????????? void Handle::SetSuccessor(Handle* succ)

??????? {????????????????????????????????????????????????????????? {

?????? public:?????????????????????????????????????????????????????????? _succ = succ;

????????????? ConcreteHandleA();?????????????????????????????????? }

????????????? ~ConcreteHandleA();????????????????????????????????? Handle* Handle::GetSuccessor()

????????????? ConcreteHandleA(Handle* succ);?????????????????????? {

????????????? void HandleRequest();?????????????????????????????????????? return _succ;

?????? protected:????????????????????????????????????????????????? }

?????? private:??????????????????????????????????????????????????? void Handle::HandleRequest()

?????? };????????????????????????????????????????????????????????? {

?????? class ConcreteHandleB:public Handle???????????????????????? }

??????? {????????????????????????????????????????????????????????? ConcreteHandleA::ConcreteHandleA()

?????? public:???????????????????????????????????????????????????? {

????????????? ConcreteHandleB();?????????????????????????????????? }

????????????? ~ConcreteHandleB();????????????????????????????????? ConcreteHandleA::ConcreteHandleA(Handle*

????????????? ConcreteHandleB(Handle* succ);?????????????????????? succ):Handle(succ)

????????????? void HandleRequest();??????????????????????????????? {

?????? protected:????????????????????????????????????????????????? }

?????? private:??????????????????????????????????????????????????? ConcreteHandleA::~ConcreteHandleA()

?????? };????????????????????????????????????????????????????????? {

?????? #endif //~_HANDLE_H_??????????????????????????????????????? }

????????????????????????????????????????????? 第? 94?? 頁 共? 105???? 頁????????????????????????????????????????? k_eckel

----------------------- Page 95-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????????http://www.mscenter.edu.cn/blog/k_eckel

?????????????????????? 代碼片斷 3:main.cpp?????????????????????????????????????????????????? 代碼片斷2:Handle.cpp

??????? //main.cpp???????????????????????????????????????????????????????? void ConcreteHandleA::HandleRequest()

??????????????????????????????????????????????????????????????????????????? {

??????? #include "Handle.h"?????????????????????????????????????????????????????? if (this->GetSuccessor() != 0)

?????????????????????????????????????????????????????????????????????????????????? {

??????? #include <iostream>????????????????????????????????????????????????????????????? cout<<"ConcreteHandleA?????????? 我把處

?????????????????????????????????????????????????????????????????????????? 理權給后繼節點....."<<endl;

??????? using namespace std;

?????????????????????????????????????????????????????????????????????????????????? this->GetSuccessor()->HandleRequest();

??????? int main(int argc,char* argv[])??????????????????????????????????????????? }

???????? {???????????????????????????????????????????????????????????????????????? else

?????????????? Handle* h1 = new ConcreteHandleA();???????????????????????????????? {

???????????????????????????????????????????????????????????????????????????????????????? cout<<"ConcreteHandleA?????????? 沒有后

?????????????? Handle* h2 = new ConcreteHandleB();???????????????????????? 繼了,我必須自己處理...."<<endl;

?????????????????????????????????????????????????????????????????????????????????? }

??????????????? h1->SetSuccessor(h2);?????????????????????????????????????? }

?????????????????????????????????????????????????????????????????????????? ConcreteHandleB::ConcreteHandleB()

??????????????? h1->HandleRequest();??????????????????????????????????????? {

??????????????? return 0;?????????????????????????????????????????????????? }

??????? }????????????????????????????????????????????????????????????????? ConcreteHandleB::ConcreteHandleB(Handle*

?????????????????????????????????????????????????????????????????????????? succ):Handle(succ)

??????????????????????????????????????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????????????????????????????????? ConcreteHandleB::~ConcreteHandleB()

??????????????????????????????????????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????????????????????????????????? void ConcreteHandleB::HandleRequest()

??????????????????????????????????????????????????????????????????????????? {

????????????????????????????????????????????????????????????????????????????????? if (this->GetSuccessor() != 0)

?????????????????????????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????????????????????????? cout<<"ConcreteHandleB?????????? 我把處

?????????????????????????????????????????????????????????????????????????? 理權給后繼節點....."<<endl;

?????????????????????????????????????????????????????????????????????????????????? this->GetSuccessor()->HandleRequest();

?????????????????????????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????????????????????????????????????????? else

?????????????????????????????????????????????????????????????????????????????????? {

???????????????????????????????????????????????????????????????????????????????????????? cout<<"ConcreteHandleB?????????? 沒有后

?????????????????????????????????????????????????????????????????????????? 繼了,我必須自己處理...."<<endl;

?????????????????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????????? 第? 95??? 頁 共? 105?????? 頁?????????????????????????????????????????????? k_eckel

----------------------- Page 96-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?代碼說明

??? Chain of Responsibility 模式的示例代碼實現很簡單,這里就其測試結果給出說明:

ConcreteHandleA? 的對象和h1 擁有一個后繼 ConcreteHandleB? 的對象h2,當一個請求到來時

候,h1 檢查看自己有后繼,于是h1 直接將請求傳遞給其后繼h2 進行處理,h2? 因為沒有后

繼,當請求到來時候,就只有自己提供響應了。于是程序的輸出為:

??? 1)ConcreteHandleA? 我把處理權給后繼節點.....;

??? 2 )ConcreteHandleB 沒有后繼了,我必須自己處理....。

?討論

???? Chain of Responsibility 模式的最大的一個有點就是給系統降低了耦合性,請求的發送者

完全不必知道該請求會被哪個應答對象處理,極大地降低了系統的耦合性。

3.10 Iterator 模式

?問題

???? Iterator? 模式應該是最為熟悉的模式了,最簡單的證明就是我在實現 Composite? 模式、

Flyweight 模式、Observer 模式中就直接用到了 STL 提供的 Iterator 來遍歷 Vector 或者 List

數據結構。

???? Iterator 模式也正是用來解決對一個聚合對象的遍歷問題,將對聚合的遍歷封裝到一個

類中進行,這樣就避免了暴露這個聚合對象的內部表示的可能。

?模式選擇

???? Iterator 模式典型的結構圖為:

????????????????????????????? 第? 96 頁 共? 105 頁????????????????????????? k_eckel

----------------------- Page 97-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????????????????? 圖2-1:Iterator Pattern 結構圖

???? Iterator 模式中定義的對外接口可以視客戶成員的便捷定義,但是基本的接口在圖中的

Iterator 中已經給出了(參考 STL 的Iterator 就知道了)。

?實現

?完整代碼示例(code)

???? Iterator 模式的實現比較簡單,這里為了方便初學者的學習和參考,將給出完整的實現

代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 97 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 98-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 1:Aggregate.h?????????????????????????????????????????????? 代碼片斷2:Aggregate.cpp

? //Aggregate.h????????????????????????????????????????????????????? //Aggregate.cpp

? #ifndef _AGGREGATE_H_????????????????????????????????????????????? #include "Aggregate.h"

? #define _AGGREGATE_H_????????????????????????????????????????????? #include "Iterator.h"

? class Iterator;??????????????????????????????????????????????????? #include <iostream>

? typedef int Object;??????????????????????????????????????????????? using namespace std;

? class Interator;?????????????????????????????????????????????????? Aggregate::Aggregate()

? class Aggregate??????????????????????????????????????????????????? {

?? {???????????????????????????????????????????????????????????????? }

? public:??????????????????????????????????????????????????????????? Aggregate::~Aggregate()

????????? virtual ~Aggregate();????????????????????????????????????? {

???????? virtual Iterator* CreateIterator() = 0;???????????????????? }

???????? virtual Object GetItem(int idx) = 0;??????????????????????? ConcreteAggregate::ConcreteAggregate()

???????? virtual int GetSize() = 0;????????????????????????????????? {

? protected:?????????????????????????????????????????????????????????????? for (int i = 0; i < SIZE; i++)

????????? Aggregate();??????????????????????????????????????????????????????????? _objs[i] = i;

? private:?????????????????????????????????????????????????????????? }

? };???????????????????????????????????????????????????????????????? ConcreteAggregate::~ConcreteAggregate()

? class ConcreteAggregate:public Aggregate?????????????????????????? {

?? {???????????????????????????????????????????????????????????????? }

? public:??????????????????????????????????????????????????????????? Iterator* ConcreteAggregate::CreateIterator()

???????? enum {SIZE = 3};??????????????????????????????????????????? {

????????? ConcreteAggregate();???????????????????????????????????????????? return new ConcreteIterator(this);

????????? ~ConcreteAggregate();????????????????????????????????????? }

????????? Iterator* CreateIterator();??????????????????????????????? Object ConcreteAggregate::GetItem(int idx)

???????? Object GetItem(int idx);??????????????????????????????????? {

????????? int GetSize();?????????????????????????????????????????????????? if (idx < this->GetSize())

? protected:????????????????????????????????????????????????????????????????????? return _objs[idx] ;

? private:????????????????????????????????????????????????????????????????? else

????????? Object _objs[SIZE];???????????????????????????????????????????????????? return -1;

? };???????????????????????????????????????????????????????????????? }

? #endif //~_AGGREGATE_H_??????????????????????????????????????????? int ConcreteAggregate::GetSize()

???????????????????????????????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????????? return SIZE;

???????????????????????????????????????????????????????????????????? }

???????????????????????????????????????????????? 第? 98??? 頁 共? 105????? 頁??????????????????????????????????????????? k_eckel

----------------------- Page 99-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????????? 代碼片斷 3:Iterator.h????????????????????????????????????????????? 代碼片斷4:Iterator.cpp

???? //Iterator.h??????????????????????????????????????????????????? //Iterator.cpp

???? #ifndef _ITERATOR_H_??????????????????????????????????????????? #include "Iterator.h"

???? #define _ITERATOR_H_??????????????????????????????????????????? #include "Aggregate.h"

???? class Aggregate;??????????????????????????????????????????????? #include <iostream>

???? typedef int Object;???????????????????????????????????????????? using namespace std;

???? class Iterator????????????????????????????????????????????????? Iterator::Iterator()

???? {??????????????????????????????????????????????????????????????? {

???? public:???????????????????????????????????????????????????????? }

???????????? virtual ~Iterator();??????????????????????????????????? Iterator::~Iterator()

??????????? virtual void First() = 0;???????????????????????????????? {

??????????? virtual void Next() = 0;???????????????????????????????? }

??????????? virtual bool IsDone()???? = 0;?????????????????????????? ConcreteIterator::ConcreteIterator(Aggregate*

??????????? virtual Object CurrentItem() = 0;??????????????????????? ag , int idx)

???? protected:?????????????????????????????????????????????????????? {

???????????? Iterator();??????????????????????????????????????????????????? this->_ag = ag;

???? private:??????????????????????????????????????????????????????????????? this->_idx = idx;

???????????????????????????????????????????????????????????????????? }

???? };????????????????????????????????????????????????????????????? ConcreteIterator::~ConcreteIterator()

???? class ConcreteIterator:public Iterator?????????????????????????? {

???? {?????????????????????????????????????????????????????????????? }

???? public:???????????????????????????????????????????????????????? Object ConcreteIterator::CurrentItem()

??????????? ConcreteIterator(Aggregate* ag , int idx =??????????????? {

???? 0);???????????????????????????????????????????????????????????????????? return _ag->GetItem(_idx);

???????????? ~ConcreteIterator();??????????????????????????????????? }

???????????? void First();?????????????????????????????????????????? void ConcreteIterator::First()

???????????? void Next();???????????????????????????????????????????? {

???????????? bool IsDone();???????????????????????????????????????????????? _idx = 0;

???????????? Object CurrentItem();?????????????????????????????????? }

???? protected:????????????????????????????????????????????????????? void ConcreteIterator::Next()

???? private:???????????????????????????????????????????????????????? {

???????????? Aggregate* _ag;??????????????????????????????????????????????? if (_idx < _ag->GetSize())

????????????????????????????????????????????????????????????????????????????????? _idx++;

???????????? int _idx;?????????????????????????????????????????????? }

???????????????????????????????????????????????????????????????????? bool ConcreteIterator::IsDone()

???? };?????????????????????????????????????????????????????????????? {

??????????????????????????????????????????????????????????????????????????? return (_idx == _ag->GetSize());

???? #endif //~_ITERATOR_H_????????????????????????????????????????? }

????????????????????????????????????????????????? 第? 99?? 頁 共? 105????? 頁???????????????????????????????????????????? k_eckel

----------------------- Page 100-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

????????????? 代碼片斷 5:main.cpp

? //main.cpp

? #include "Iterator.h"

? #include "Aggregate.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

?????? Aggregate*????????? ag?????? =?????? new

? ConcreteAggregate();

??????? Iterator* it = new ConcreteIterator(ag);

??????? for (; !(it->IsDone()) ; it->Next())

??????? {

???????????? cout<<it->CurrentItem()<<endl;

??????? }

??????? return 0;

? }

?代碼說明

????? Iterator 模式的實現代碼很簡單,實際上為了更好地保護Aggregate 的狀態,我們可以盡

量減小Aggregate 的public 接口,而通過將Iterator 對象聲明位Aggregate 的友元來給予Iterator

一些特權,獲得訪問Aggregate 私有數據和方法的機會。

?討論

????? Iterator 模式的應用很常見,我們在開發中就經常會用到 STL 中預定義好的Iterator 來對

STL 類進行遍歷(Vector、Set 等)。

3.11 Interpreter 模式

?問題

????????????????????????????????????????? 第? 100? 頁 共? 105??? 頁????????????????????????????????????? k_eckel

----------------------- Page 101-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??? 一些應用提供了內建(Build-In )的腳本或者宏語言來讓用戶可以定義他們能夠在系統

中進行的操作。Interpreter 模式的目的就是使用一個解釋器為用戶提供一個一門定義語言的

語法表示的解釋器,然后通過這個解釋器來解釋語言中的句子。

???? Interpreter 模式提供了這樣的一個實現語法解釋器的框架,筆者曾經也正在構建一個編

譯系統Visual CMCS,現在已經發布了Visual CMCS1.0 (Beta),請大家訪問Visual CMCS 網

站獲取詳細信息。

?模式選擇

???? Interpreter 模式典型的結構圖為:

???????????????????????? 圖2-1:Interpreter Pattern 結構圖

???? Interpreter 模式中,提供了TerminalExpression 和NonterminalExpression 兩種表達式的解

釋方式,Context 類用于為解釋過程提供一些附加的信息(例如全局的信息)。

?實現

?完整代碼示例(code)

???? Interpreter 模式的實現比較簡單,這里為了方便初學者的學習和參考,將給出完整的實

現代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

????????????????????????????? 第? 101 頁 共? 105 頁???????????????????????? k_eckel

----------------------- Page 102-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?????????????? 代碼片斷 1:Context.h????????????????????????????????????????????? 代碼片斷2:Context.cpp

? //Context.h???????????????????????????????????????????????????? //Context.cpp

? #ifndef _CONTEXT_H_???????????????????????????????????????????? #include "Context.h"

? #define _CONTEXT_H_

????????????????????????????????????????????????????????????????? Context::Context()

? class Context?????????????????????????????????????????????????? {

? {

? public:???????????????????????????????????????????????????????? }

???????? Context();

????????????????????????????????????????????????????????????????? Context::~Context()

???????? ~Context();????????????????????????????????????????????? {

? protected:????????????????????????????????????????????????????? }

? private:

? };

? #endif //~_CONTEXT_H_

?????????????????????????????????????????????? 第? 102?? 頁 共? 105???? 頁?????????????????????????????????????????? k_eckel

----------------------- Page 103-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼??????????????????????????????????????????????????http://www.mscenter.edu.cn/blog/k_eckel

?????????????????? 代碼片斷 3:Interpret.h?????????????????????????????????????????????? 代碼片斷4:Interpret.cpp

???? //Interpret.h????????????????????????????????????????????????????? //interpret.cpp

???? #ifndef _INTERPRET_H_????????????????????????????????????????????? #include "Interpret.h"

???? #define _INTERPRET_H_????????????????????????????????????????????? #include <iostream>

???? #include "Context.h"?????????????????????????????????????????????? using namespace std;

???? #include <string>????????????????????????????????????????????????? AbstractExpression::AbstractExpression()

???? using namespace std;?????????????????????????????????????????????? {

???? class AbstractExpression?????????????????????????????????????????? }

????? {???????????????????????????????????????????????????????????????? AbstractExpression::~AbstractExpression()

???? public:??????????????????????????????????????????????????????????? {

???????????? virtual ~AbstractExpression();???????????????????????????? }

??????????? virtual void Interpret(const Context& c);?????????????????? void?????????? AbstractExpression::Interpret(const

???? protected:???????????????????????????????????????????????????????? Context& c)

???????????? AbstractExpression();????????????????????????????????????? {

???? private:?????????????????????????????????????????????????????????? }

???? };???????????????????????????????????????????????????????????????? TerminalExpression::TerminalExpression(const

???? class???????????????????? TerminalExpression:public??????????????? string& statement)

???? AbstractExpression???????????????????????????????????????????????? {

????? {?????????????????????????????????????????????????????????????????????? this->_statement = statement;

???? public:??????????????????????????????????????????????????????????? }

???????????? TerminalExpression(const??????????????? string&??????????? TerminalExpression::~TerminalExpression()

???? statement);??????????????????????????????????????????????????????? {

???????????? ~ TerminalExpression();??????????????????????????????????? }

??????????? void Interpret(const Context& c);?????????????????????????? void?????????? TerminalExpression::Interpret(const

???? protected:???????????????????????????????????????????????????????? Context& c)

???? private:?????????????????????????????????????????????????????????? {

???????????? string _statement;??????????????????????????????????????????????? cout<<this->_statement<<"

???? };???????????????????????????????????????????????????????????????? TerminalExpression"<<endl;

???? class???????????????? NonterminalExpression:public???????????????? }

???? AbstractExpression???????????????????????????????????????????????? NonterminalExpression::NonterminalExpressio

????? {???????????????????????????????????????????????????????????????? n(AbstractExpression* expression,int times)

???? public:??????????????????????????????????????????????????????????? {

???????????? NonterminalExpression(AbstractExpressi??????????????????????????? this->_expression = expression;

???? on* expression,int times);?????????????????????????????????????????????? this->_times = times;

???????????? ~ NonterminalExpression();???????????????????????????????? }

??????????? void Interpret(const Context& c);?????????????????????????? NonterminalExpression::~NonterminalExpressi

???? protected:???????????????????????????????????????????????????????? on()

???? private:?????????????????????????????????????????????????????????? {

???????????? AbstractExpression* _expression;?????????????????????????? }

???????????? int _times;??????????????????????????????????????????????? void????? NonterminalExpression::Interpret(const

???? };???????????????????????????????????????????????????????????????? Context& c)

???? #endif //~_INTERPRET_H_??????????????????????????????????????????? {

????????????????????????????????????????????????????????????????????????????? for (int i = 0; i < _times ; i++)

?????????????????????????????????????????????????????????????????????????????? {

?????????????????????????????????????????????????? 第? 103??? 頁 共? 105?????? 頁??????? this->_expression->Interpret(c); k_eckel

?????????????????????????????????????????????????????????????????????????????? }

??????????????????????????????????????????????????????????????????????? }

----------------------- Page 104-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼???????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

??????????? 代碼片斷 5:main.cpp

? //main.cpp

? #include "Context.h"

? #include "Interpret.h"

? #include <iostream>

? using namespace std;

? int main(int argc,char* argv[])

? {

?????? Context* c = new Context();

?????? AbstractExpression*?? te? =???? new

? TerminalExpression("hello");

??????? AbstractExpression* nte?? =?? new

? NonterminalExpression(te,2);

??????? nte->Interpret(*c);

??????? return 0;

? }

?代碼說明

????? Interpreter 模式的示例代碼很簡單,只是為了說明模式的組織和使用,實際的解釋

Interpret 邏輯沒有實際提供。

?討論

????? XML 格式的數據解析是一個在應用開發中很常見并且有時候是很難處理的事情,雖然

目前很多的開發平臺、語言都提供了對XML 格式數據的解析,但是例如到了移動終端設備

上,由于處理速度、計算能力、存儲容量的原因解析XML 格式的數據卻是很復雜的一件事

情,最近也提出了很多的移動設備的XML 格式解析器,但是總體上在項目開發時候還是需

要自己去設計和實現這一個過程(筆者就有過這個方面的痛苦經歷)。

???? Interpreter 模式則提供了一種很好的組織和設計這種解析器的架構。

???? Interpreter 模式中使用類來表示文法規則,因此可以很容易實現文法的擴展。另外對于

終結符我們可以使用Flyweight 模式來實現終結符的共享。

???????????????????????????????????? 第? 104 頁 共? 105? 頁????????????????????????????????? k_eckel

----------------------- Page 105-----------------------

設計模式精解-GoF 23 種設計模式解析附C++實現源碼????????????????????????? http://www.mscenter.edu.cn/blog/k_eckel

?4?? 說明

?????? Project???? Design Pattern Explanation with C++ Implementation (By K_Eckel)

? Authorization??? Free Distributed but Ownership Reserved

????? Date????????? 2005-04-05 (Cherry blossom is Beautiful)——2005-05-04

??? Test Bed?????? MS Visual C++ 6.0

?????????????????????????????????? 第? 105 頁 共? 105? 頁?????????????????????????????? k_eckel


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/454897.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454897.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454897.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HihoCoder 1323 回文字符串

回文字符串 思路 動態規劃&#xff1a; 可以有三種修改決策 將開頭和結尾字符改成一樣在開頭加一個和末尾相同的字符在末尾加一個和開頭形同的字符代碼&#xff1a; #include <stdio.h> #include <iostream> #include <string.h> using namespace std; char …

python線程狀態_Python線程

1. 線程基礎1.1. 線程狀態線程有5種狀態&#xff0c;狀態轉換的過程如下圖所示&#xff1a;1.2. 線程同步(鎖)多線程的優勢在于可以同時運行多個任務(至少感覺起來是這樣)。但是當線程需要共享數據時&#xff0c;可能存在數據不同步的問題。考慮這樣一種情況&#xff1a;一個列…

JavaScript中錯誤正確處理方式,你用對了嗎?

JavaScript的事件驅動范式增添了豐富的語言&#xff0c;也是讓使用JavaScript編程變得更加多樣化。如果將瀏覽器設想為JavaScript的事件驅動工具&#xff0c;那么當錯誤發生時&#xff0c;某個事件就會被拋出。理論上可以認為這些發生的錯誤只是JavaScript中的簡單事件。 本文將…

文件分割機

文件分割與合并 要求&#xff1a;實現對大文件的分割與合并。 按指定個數切&#xff08;如把一個文件切成10份&#xff09;或按指定大小切&#xff08;如每份最大不超過10M&#xff09;&#xff0c;這兩種方式都能夠。 程序說明&#xff1a; 文件分割&#xff1a;把一個文件分割…

mysql pow函數怎么用_pow函數怎么用

PHP pow函數表示指數表達式。pow函數怎么用&#xff1f;php pow()函數 語法作用&#xff1a;pow()函數的作用是將一個數進行n次方計算后返回語法&#xff1a;pow(X,Y);參數&#xff1a;X表示要做處理的數字Y表示指定n次方中的n數值說明&#xff1a;返回X的Y次方冪&#xff0c;如…

【IntelliJ IDEA】添加一個新的tomcat,tomcat啟動無法訪問歡迎頁面,空白頁,404

第一部分&#xff0c;添加一個tomcat 1.先把Toolbar 和 Tool Buttons顯示出來 2.選擇Edit Configurations 3.添加一個新的tomcat server進來 解決no artifacts configured問題&#xff0c;就是沒有項目加入里面 先添加一個沒有的項目 啟動之后找不到 頁面 第二部分&#xff0c…

回文數-時間變換-判斷郵箱

class huiwenshu public class huiwenshu {public static void main(String[] args) {System.out.println("輸入...");Scanner in new Scanner(System.in);String number in.next();boolean flag true;for(int i0;i<number.trim().length()/2;i){if(!String.va…

mac eclipse tomcat mysql_mac下使用eclipse+tomcat+mysql開發 j2ee(一)

在這里是使用eclipse&#xff0b;tomcat&#xff0b;mysql的方式。1、軟件下載(1) eclipse我使用的是mac&#xff0c;因為本人是蘋果客戶端開發者&#xff0c;所以目前只有蘋果機器了。首先下載eclipse for mac&#xff0c;選擇mac 64位&#xff0c;下載eclipse-jee-kepler-SR1…

社交系統ThinkSNS-plus(TS+)V1.0發布!

2019獨角獸企業重金招聘Python工程師標準>>> 需要購買源碼的同志們&#xff0c;依然隨時可以聯系我們手機&#xff1a;18108035545&#xff08;同微信&#xff09;&#xff1b;電話&#xff1a;028-82884828 &#xff1b;QQ&#xff1a;3298713109&#xff1b; 從決…

《軟件架構設計》一書目錄

第一部分 軟件架構概念與思想篇 1 第1章 解析軟件架構概念 3 1.1 軟件架構概念的分類 3 1.1.1 組成派 4 1.1.2 決策派 5 1.2 軟件架構概念大觀 5 1.2.1 Booch、Rumbaugh和Jacobson的定義 5 1.2.2 Woods的觀點 6 1.2.3 Garlan和Shaw的定義 6 1.2.4 Perry和Wolf的定義 …

.net 讀取mysql數據庫配置文件_.NETCore添加及讀取默認配置文件信息

這里的默認配置文件指的是項目中的appsettings.json文件&#xff0c;我們可以把一些配置信息保存在里面&#xff0c;比如數據庫連接信息。來吧&#xff0c;看例子&#xff1a;1、先在appsettings.json文件中寫入數據庫的連接信息&#xff1a;{"Logging": {"LogL…

年齡層統計SQL

-- 處理名單丟失SELECT u.user_id u_userid,o.user_id o_userid,o.* FROMtb_gh_orders o LEFT JOIN tb_gh_user u ON o.user_id u.user_id WHERE o.course_id 128 AND o.order_state 1 ;-- 年齡段統計SELECT T1.*,CONCAT(LEFT (T1.C1 / T2.C2 * 100, 5), %) P FROM(SELECT C…

h5 img js 點擊圖片放大_H5實現移動端圖片預覽:手勢縮放, 手勢拖動,雙擊放大......

查看示例效果&#xff1a;一、功能介紹圖片預覽主要有以下幾個功能點組成&#xff1a;監聽圖片點擊事件&#xff0c;進入圖片預覽模式自定義手勢事件, (雙指縮放&#xff0c;滑動&#xff0c;雙擊。。。)監聽圖片手勢事件&#xff0c;通過 transform-matrix 實現圖片的各種變換…

[轉載]建立團隊溝通協作工作方式

很多初創團隊、以及剛開始嘗試敏捷的團隊&#xff0c;沒有工作協議的概念&#xff0c;熱熱鬧鬧&#xff0c;混混亂亂。本文介紹了關于工作協議的What, Why, Who, When, 以及How。 What:什么是工作協議 工作協議&#xff1a;由團隊共同商議&#xff0c;達成一致遵守的一組規則、…

私有云促進企業管理變革 助力企業快步前行

在全球經濟迅速發展和科學技術突飛猛進的情況下, 無論是制造型企業還是服務型行業&#xff0c;企業數量都在迅速增加,產品和服務質量也日趨完善。這必然導致一個結果——企業間的競爭更加激烈、產品的同質化現象日益明顯。在這樣的大背景之下, 再伴隨著現代管理和營銷理論的不斷…

linux安裝自帶mysql嗎_Linux下安裝mysql

前提下必須要有這三個文件夾A.jpgB.jpg還要安裝這兩個軟件&#xff1b;直接百度官網即可&#xff1b;先通過Xftp6這個軟件&#xff0c;編譯文件夾&#xff0c;C.jpg搭建mysql1.查看CentOS自帶的mysqlrpm -qa | grep mysql2.卸載CentOS自帶的mysqlrpm -e --nodeps 要卸載的軟件3…

Android深入源代碼分析理解Aidl總體調用流程(雷驚風)

2017年開始上班的第一天。老不想工作了&#xff0c;假期感覺還沒開始就已經結束了&#xff0c;唉&#xff0c;時間就是這樣&#xff0c;新的一年開始了&#xff0c;盡管非常不想干正事&#xff0c;沒辦法&#xff0c;必須干起來。由于后邊的路還非常長&#xff0c;距離六十歲還…

(轉載)UI接口分層自動化測試框架設計思想

閱讀本小節&#xff0c;需要讀者具備如下前提條件&#xff1a; 1. 掌握一種編程語言基礎&#xff0c;如java、python等。 2. 掌握一種單元測試框架&#xff0c;如java語言的testng框架、python的unittest框架。 3. 掌握目前主流的UI測試框架&#xff0c;移動端APP測試框架Ap…

如何提高閱讀源代碼的效率 .

如何提高閱讀源代碼的效率 記得在開源流行之前&#xff0c;我看過的代碼緊限于所參與的項目&#xff0c;能有個幾萬行就不錯哩。后來很多優秀開源項目都相繼蹦出來了&#xff0c;閱讀的代碼量那叫一個大呀&#xff01;不得不看。我現在掉到android這個大坑里&#xff0c;每天都…

170821-關于SpringMVC的知識點

1.SpringMVC 概述以及優勢 SpringMVC和Spring的關系&#xff1a; 軟件開發的三層架構&#xff1a; web層【表示層、表現層】---->Service層---->Dao[DataBase Access Object]---->數據庫&#xff01; SpringMVC實際上是Spring的一個子模塊&#xff0c;我們用Spring…