看透物件導向的複用技術

raychase.net發表於2012-10-15

  本文翻譯自這篇文章,這篇文章寫於1998年,作者是Scott Ambler,真的挺久遠了。看看上個世紀末的時候,程式設計師的視角和觀點。

  想從物件導向複用技術中真正獲益,你就必須理解不同種類的複用,並且自如地在不同場合下使用它們。

  • 可複用資源
  • 業務物件根源

  複用性是物件導向技術帶來的很棒的潛在好處之一。遺憾的是,很多情況下這個好處並不能真正兌現。原因在於複用並不是毫無代價的,它並不是你使用物件導向開發工具的時候就能輕而易舉得到的。相反,它是你為了成功而努力工作得來的。首先要知道的是,這個世界上有比程式碼複用多得多的可複用的東西。程式碼複用只不過是最基本的一種形式而已。當然,你不要誤解我的意思,程式碼複用當然是個好東西,只不過你可以靠其它種類的複用來取得更大的成就罷了。這裡你會更關注整個應用,而不是原始碼,那麼你當然就可以複用其它的東西,而不只是程式碼。讓我們來仔細看看各種複用的方式吧,怎麼在你構建應用的時候恰當地應用它們。

  程式碼複用

  程式碼複用,是最常見的複用,指的是在同一個應用的多個模組中,或者是在多個應用下原始碼的複用。理想狀況下,程式碼複用可以共享通用類、函式集合或過程(在C++中是可以的,不過Smalltalk和Java不支援)來實現;即便是在最差的情況下,程式碼複用也可以通過拷貝和修改原始碼來實現。現在,讓我們回到糟糕的現實,工業生產對於程式碼複用還停留在僅僅是開發者拷貝貼上程式碼的階段。

  程式碼複用的一個關鍵因素是你要能夠獲取到原始碼。如果必要的話,你自己可以修改這段程式碼,當然也可以找別人幫你修改。這一點好壞並存,通過審讀程式碼,你可以自己決定——哪怕這個決定很難做出——你是否要複用這段程式碼。同時,把程式碼開放給你,那麼程式碼原作者也許會失去撰寫說明文件的動力,這也就增加了你理解它所花費的時間,減小了你可能獲得的收益。

  程式碼複用的最大好處在於它可以減少你的程式碼量,也就潛在地減小了開放和維護成本。壞處則在於你自己應用的能力範圍就被約束住了,而且也增加了應用和被複用程式碼之間的耦合。

  繼承複用

  繼承複用指的是在你的應用裡面使用繼承技術,以獲取被繼承類已經具備的行為,進而從對已有類的利用中獲得優勢。繼承是物件導向核心基礎的概念之一,適用於模型中“is a”、“is like”和“is kind of”這樣的關係。舉例來說,要開發一個CheckingAccount這樣的類,你就得繼承自SavingsAccount,直接複用它已有的行為來實現。

  繼承複用的好處在於你可以充分利用以前實現過的行為,減少開發時間,也就減少了你完成整個應用的開銷。不幸的是,繼承複用也有一些明顯的壞處。首先,對繼承的誤用經常會讓開發者失去元件複用這種更高層次複用的機會。其次,新人對於繼承類的迴歸測試不夠細緻(父類和子類都要進行足夠的測試),會導致產生一個不易維護和擴充套件增強的脆弱繼承結構。總之,正如你所見,繼承複用確有其物,但是代價太大。

  模板複用

  模板複用是文件複用的一種典型表現形式。它指的是對組織中關鍵開發文件、模型和原始碼統一規劃的實踐。舉例來說,組織中採用統一的文件模板來記載用例、狀態報告、開發時間表、變更請求、使用者需求、類檔案和方法定義的文件頭部。採用文件模板的最大缺點在於開發者會為了他們的使用方便而修改它們,卻沒能及時告知他的同事。

  使用模板的理想結果,就是可以讓開發者的工作變得簡單。我見過開發人員共享像Microsoft Word一樣簡單的模板,也見過如Lotus Notes資料庫一樣複雜的模板。你的組織成員必須訓練何時和怎樣來使用模板,這樣每一個人才會去使用並且正確地使用它們。

  元件複用

  元件複用指的是對預先構建和良好封裝的元件進行復用的過程。元件往往是一個職責簡單但五臟俱全的個體。元件複用和程式碼複用的區別在於,你是不可以訪問到元件的原始碼的。而它和繼承複用的區別則在於,它不使用子類。元件複用的一個典型例子就是Java Beans和ActiveX。

  元件複用的好處有很多。首先,它比程式碼複用或者是繼承複用提供了更大的可複用性,因為元件是完整獨立的個體,只需要把它引入就可以使用了。其次,由於通用平臺的廣泛使用,如Win32作業系統和Java虛擬機器,為第三方廠商低成本建立和營銷元件來獲取利潤提供了市場。元件複用最大的壞處在於元件很小,而且功能單一,你卻可能需要為它們引入大量的庫。

  使用元件最簡單的方式可以從使用使用者介面widget的滑動條、圖形元件和影象按鈕開始(比如嘗試去給它們取新的名字)。但是別忘了,一款應用可不僅僅只有使用者介面。你可以獲得像網路訪問這樣的作業系統功能特性,也可以獲得像連線資料庫來持久化資料的能力。如果你要構建自己的元件,請確保它功能單一,即只做一件事情。舉例來說,一個編輯地址的使用者介面元件可以具備很高的複用性,因為你可以在很多編輯介面上使用它。反之,一個同時具備編輯地址、e-mail和手機號碼的使用者介面元件複用性就比較差了,因為你通常不需要同時具備這三個功能。因此,最好的辦法是拆分這三個功能,單獨構建和在需要的地方重用每一個可複用元件。如果一個元件只做一件事情,那它就是一個高內聚的元件。

  框架複用

  框架複用指的是使用通用技術和業務物件,完成這樣的一組類來實現基礎的功能。開發者以框架作為應用構建的基礎,也就是說,80%的活框架都替你做完了,你只需要完成剩下20%的工作。一種常見的形式是,讓框架來完成GUI的基礎元件。如今已有很多保險、人力資源、製造業、銀行和電子商務方面的框架。框架複用體現了一種位於領域層面的高階複用。

  框架總是為某一個問題域提供一個初始解決方案的,而且隨著業務邏輯複雜化,需要耗費數年才能真正完善起來。框架的複雜性使得掌握它變得困難,需要開發者長期的學習過程。框架往往定位於特定平臺上,把你視作它普通的使用者,這也增加了你的應用的風險。雖然框架幫你完成了80%的工作,但是最困難的部分,業務邏輯和處理流程是你的組織所特有的,不得不由你完成。框架之間很難相容,除非它們是一個人完成的,或者是同一個供應商提供的。這需要你不得不改變你的業務邏輯,以適應這個框架。

  工件複用

  工件複用指的是使用對以前建立的工件用例、標準文件、領域模型、過程指導和其它,來幫助你開始一個新工程。工件複用分為幾個層次,從完整的拿來即用這種100%的完全複用,到僅以工件作模型之用,研究分析之以獲取靈感。舉例來說,編碼和使用者介面設計的標準文件對不同的專案來說,就是有價值的工件,像其中的建模符號定義和方法論總覽這種文件,是可以直接複用的。我曾經為已有的通用資料介面以物件導向的方式做了包裝,讓這些類使用起來更直觀。

  工件複用提升了專案間的一致性,減少了各個專案的管理成本。另一個好處是你總是可以從網上發現和購買很多工件:使用者介面標準對絕大多數平臺來說都是很常用的;編碼標準對主要語言來說都是不可或缺的;而標準物件導向方法論和模型記號這樣的東西已經使用好多年了。主要的壞處在於很多核心程式設計師總覺得這種複用過了頭,給彼此帶來了強加的標準和過程約束。因此工件複用的底線就是當你覺得它是一種重要、可行和醒目的技術時,再去使用它。

  模式複用

  模式複用指的是使用公眾總結認可的途徑去解決常規問題。模式往往可以用1到5個類組成的簡單類圖來表達。模式複用,和程式碼複用顯著不同的地方在於,你其實是在複用隱藏在程式碼後面的思想。模式複用是複用的高階形式,它被證明有很長的生命週期,至少超越了你正在使用的計算機語言,甚至超越物件導向範型本身。

  “接觸點(Contact Point)模式”,來自於我的一本叫做《Building Object Applications That Work》的書,它使用了UML1.1類圖來建模,展示了一個尋找你的組織和其它業務實體之間接觸點的通用模式。在這個模式下,你可以把郵件地址、實際地址和電話號碼這些要素,都視作同一類供組織和其它業務實體(客戶、僱員、供應商等等)互動的物件接觸點。這個模式增加了應用的靈活性,你不但可以把發票以郵件形式發給你的客戶,而且還可以決定是要以e-mail形式還是傳真形式。你可以以電子產品的形式傳輸這個產品,而不是非得配送一張CD-ROM或者一盒視訊磁帶到某個地址去。接觸點模式就是做這些事的關鍵先生。我已經成功分析了幾類應用關於接觸點模式的實現,複用了裡面最困難的部分——為你思考背後的東西建模。模式複用是一種高階的複用,你完全可以用不同語言、不同平臺去實現它。模式蘊含著最重要的開發價值——解決問題的思路。模式增加了使用常規途徑維護和增強應用解決問題的能力,對於物件導向的開發者來說,價值是顯而易見的。壞處在於模式複用並不能提供一種得之即用的解決方案,你不得不親自實現模式的實際程式碼。

  領域元件複用

  領域元件複用指的是識別和開發大規模的可複用業務元件。領域元件是相關領域和業務類緊密結合的一組類。電信公司的元件圖就包含若干領域元件,而每個元件都封裝了一組類。服務提供元件封裝了一百多個類,用以為遠端呼叫、有線電視和網際網路服務。在新應用的開發階段,領域元件通過架構驅動的模型訪問,修改和增強。

  領域元件已經顯出巨大的可複用潛能,因為它們反映出大規模的業務行為內聚的特徵,在許多應用中都是一致的。你在領域開發中創造的每樣東西都是可以複用的。與後期的複用相比,領域元件在前期業務行為和組織的架構設計中顯出更大的作用。

  對以上的複用方法,好訊息是,它們是可以同時被採用的。框架複用經常會將你的設計限制在框架的架構和使用規則的侷限上,但是你仍然可以在框架上面好好利用其它的複用方式。工件和元件複用是最容易上手的形式,只需要一點點的調查,很容易就找到可複用的工件或元件。

  你可以線上訂購文件模板,但是如果你的組織沒有制定完好的開發流程,你也許從這些模板中獲得不了太多東西。繼承和模板複用是建模工程師熟悉的領域,其實從一開始他們就在採用這些複用形式了。

  現實地說,我會以工件和模板複用開始,來訓練我的建模工程師,正確使用繼承和模式複用,來以架構驅動方式識別開發領域模型的元件,我相信程式設計師會盡可能地複用它們。

  分類視角

  既然我們已經掌握一些可複用工具了,那就讓我們來看看該怎麼用吧。總共有4層架構分類,標識著我們對相應每一層的複用能力。因為每一層都有它自己特有的屬性和開發方法,因此試著在每一層培養複用技巧是相當有意義的。現在讓我們具體來看。

  使用者介面層封裝了螢幕顯示和報告資訊,能夠體現出使用者和應用互動的情況。介面層最常見的複用型別,顯然是介面widget的元件複用,因此開發者很可能會購買滾動條、影象、連結串列和其它widget的元件庫。最重要的層次是工件複用,特別是使用者介面和報告資訊佈局標準的複用。在介面設計中最重要的一件事是一致性,最簡單的辦法是採用標準和原則來構建你的應用。

  業務層封裝了應用的問題域邏輯。模式複用,尤其是分析模式複用,和框架複用的業務模型與通用業務類庫的複用一樣,是業務層十分重要的事。雖然這三種複用方法的應用還遠沒成熟,但它們在業務領域中的發展卻是非常迅猛的。大型模式集合在學術和商業界爭先發展,通用框架在具備垂直市場的大型諮詢和技術公司不斷被重構優化。

  業務層更重要的複用,還是在你的組織中真正引入領域元件。架構驅動的開發是基於複用的,領域元件和產品一樣重要。

  持久層的封裝和一般化,採用多種持久化機制,永久地存放物件到關聯式資料庫、物件資料庫或者文字檔案中去。這一層複用最重要的形式是框架複用和元件複用。這是因為你可以購買完整或者部分實現持久層的包。模式複用也可能很重要,持久層的設計會以多種形式展現出來。此外,組織中資料字典的工件複用也可能會成為重要的一份子。

  系統層封裝和一般化了作業系統、網路、硬體和其它應用。設計模式複用,尤其是硬體和應用的包裝,在系統層中是非常普遍的,以元件和工件複用的形式表現出來。

  在這4層內部,程式碼和繼承複用顯然是最有價值的。當然,你也可以爭辯說模式複用可以在使用者介面層中實現。對一個完整的專案來說,標準文件佈局和開發標準、過程下的模板複用也是不容忽視的。

  複用的成功之匙

  那麼,怎樣才能真正做到物件導向複用呢?我想說,你應該這樣開始:去買一堆工具,還有一個倉庫來存放你可複用的的工作成果。可惜的是,複用可不僅僅是工具而已。事實上,很多組織都因為過於專注於工具而不是過程可悲地失敗了。這裡有一些複用的小訣竅:

  • 你只能在某樣東西至少在不同專案裡被複用三次以上以後,才能稱呼它為可複用的。你可以嘗試可複用的設計,但是直到你的設計被複用三次,你才可以談成功的設計。可複用性是旁觀者來下結論的,而不是設計者自己。
  • 可複用性必須保證文件完備,至少具備一個怎樣使用的實際例子。此外,文件必須標識出,什麼時候不要複用它,這樣開發者才能理解合適場景的上下文。
  • 真正實現複用的唯一途徑是好好準備它。你必須分配必要的時間和資源來確保你的工作可複用。如果你不回首花時間來一般化你的工作,複用就不可能發生。專案壓力會迫使你把可複用化的工作擱置,直到你真的有時間去完成它。在這裡,底線就是對複用的管理,特別是對已有資源的複用,把它們持續加到可複用倉庫中,這可能並不是你當前工作的一部分,但是你不做,複用就無從談起。
  • 複用是一種態度。當你新建一個工程的時候,第一件事應該是決定你的應用還會以怎樣的方式在別的場合被複用。也許有些人已經構建了你需要的東西,或者你可以購買一些其它可複用元件。另一方面,你得主動分享你的工作成果,這樣大家才可以複用它。一個好領隊會在團隊中持續地尋找複用點和提升、獎勵複用的機會。一個不錯的方式就是在從這樣兩個方面去尋找可複用的機會:模型評審過程中,尋找繼承和模式複用的機會;程式碼走讀過程中,尋找元件和程式碼複用的機會。

  有時你會患上“非我發明”(NIH)綜合症,這是一個阻止你在不同團隊中傳播複用精神的壁壘。由於NIH綜合症,開發者沒法複用其他團隊的工作成果,僅僅是因為這些東西不是自己創造的。這種邏輯真是狗屎啊,職業的開發者會在工作中持續地尋找可複用的機會,因為那會將他們從繁重工作中解放出來,有更大的精力去關注那些他們自己應用中特有的問題。我的經驗是,只要職業開發者遇到了滿足當前需求的,高質量、文件完備和易於理解的元件,他們會很快地複用它們。NIH綜合症就是一個笑談,如果那樣的話,物件導向開發環境不應該關聯那麼多類庫,成百上千的靠賣可複用元件和框架的公司就倒閉了。

  我們總是在說人們怎麼去發現那些可複用的東西,沒錯,這裡我還要說,複用倉庫真是一個好東西,它和組織命令中的官方鏈的概念差不多。就像通過官方渠道和通過私交網路的比較一樣,你可以同時在倉庫和你朋友那裡發現可複用的元件。

  可複用是一個組織級別的事情,而不是一個專案級別的事情。很多組織在嘗試複用的過程中失敗了,因為他們根本不理解這一區別。專案之間的複用,是指你因複用的獲益並不是在當前專案。很多組織在他們沒有完成第一個專案的時候就過早地放棄複用了,如果這樣你就覺得沒啥可複用的,那這想法就太愚蠢了。這就是為什麼架構驅動開發如此重要,因為它超越了單個專案的需求,是為了滿足整個組織的需求的事,一個重要的組織層面的需求,就是要儘可能複用已有的工作成果。

  一個萬能的可複用解決方案是不可能實現的。有很多不同的可複用元件,都是為了滿足特異的不同層面的需求,需要不同的處理方式。因此你需要準確地識別和適宜地計劃。

  理解不“重複發明輪子”的含義,首先你至少具備不止一個輪子。你可以複用原始碼、元件、開發工件、模式和模板。最重要的是,你的工作不是可複用的,而且它是物件導向的。那麼,你就該花時間把它變成可複用的。

相關文章