從系統論的角度看待軟件設計開發模式

發信人: dych (一萬年太久), 信區: SoftEng
標  題: 從系統論的角度看待軟件設計開發模式(全)
發信站: BBS 水木清華站 (Tue Dec 24 07:58:45 2002)

從系統論的角度看待軟件設計開發模式

學習軟件開發和程序設計十幾年,看過不少書籍和討論文章,但總給人一種隔靴撓癢,未
得要領之感。本文試圖換一個角度來探討軟件設計開發模式問題,希冀對初學者和有一定
經驗的同行們能有所裨益。若果能起到拋磚引玉的作用,餘倍感欣慰矣。
系統的結構越精巧,其運行效率也越高,穩健性也越差,實現起來也越困難。
軟件設計開發過程中遇到的幾個主要矛盾:
1。系統的功能分解與結構分解的矛盾。
2。系統的靜態結構(空間結構)與動態結構(空時結構)的矛盾。
3。系統的全局性與人的視野局部性的矛盾。

開發軟件的目的是爲了實現功能,滿足需要。通常在一個軟件中有許多功能需要同時得到
滿足,而實現起來又不能一蹴而就,所以就有了功能分解的必要。此所謂分而治之(Divi
de and Conquer)。功能分解是屬於設計描述層面的,不是實現層面的。本文強調的結構
分解才屬於實現層面,而且通過結構分解把描述與實現聯繫起來了。從描述層面向實現層
面跨越需要通過解決功能分解與結構分解的矛盾來實現。功能分解與結構分解並不是一一
對應的,因爲一種功能往往可以通過多種不同的結構來實現,而一種結構也可以實現多種
不同的功能。我們希望尋找到功能與結構之間最自然的對應關係。
熟悉計算模型的人,(若不熟悉,推薦你看Sipser的《計算理論導引》)會知道計算的基
本單位是圖靈機(TM),每個圖靈機有一個入口和一個出口,圖靈機處理字符串,通過其
內部一系列的狀態轉換,將輸入的字符串變換成輸出的通常是不同的字符串。圖靈機是最
基本的完整的計算單元。每個圖靈機既是結構單元,又是實現確定功能的實現單元,是我
們尋找的功能分解與結構分解的交叉點,是理想的原子單元。按照我們的觀點,幾條C語言
語句和C++類都不是圖靈機,因爲它們不滿足圖靈機有且只有一個入口和一個出口的要求。
而大家熟悉的許多函數,子程序以及完整的C語言及任何高級語言應用程序都可看成是圖靈
機。一臺計算機可看作是通用圖靈機(UTM),它可以模擬其它任何圖靈機的運行。我們把
這種基本的完整的計算單元稱作組件或模塊(Component/Unit)。注意每個組件是一個獨
立的個體,通過其唯一的入口和出口與外界交換信息。組件可大可小,大到可以是整個軟
件,整個系統,小到可以是由幾個語句組成的一個函數。組件實現了功能的封裝,它擁有
一個名字以及說明它所實現功能的描述。組件起到了聯繫功能分解與結構分解的橋樑作用

面向對象程序設計的類其本質是要實現封裝和重用兩大功能。封裝就是分成內外兩部分,
隔離開來,做到內外有別。內部的變量和操作對外部不可見,外部只能通過暴露在外的接
口與內部通訊。類的封裝並不徹底,因爲外部可以直接調用其公共變量和公共函數。這可
看作是爲了使用的靈活方便而犧牲了概念的完整性的一個典型例子。再看重用。通常類是
通過繼承機制來實現重用的。筆者認爲繼承並不是實現重用的一種自然的機制,更不是唯
一的機制。很多情況下,只是爲了重用類的一小部分代碼,硬是使用繼承機制把兩個類說
成是父子類的類屬關係,顯得十分牽強而且笨拙。濫用類的繼承機制的後果也是可怕的。
想一想VC的MFC類庫和Java類庫那些龐雜而笨重的繼承關係,你感到的不是清晰,更多的是
一種混亂,牽強附會,破綻百出。何況類的繼承機制過於靈活,即使很有經驗的程序員也
難以恰如其分地理解和運用,不同的程序員使用起來風格迥異,相互之間難於理解和溝通

面向對象程序設計中類的概念,由於其封裝的不徹底,繼承式重用機制的缺陷使我們考慮
放棄使用類的概念。那我們怎樣實現代碼重用呢?我們可以使用組件組裝機制和框架來實
現重用。
按照前面的定義,一個組件就是一臺圖靈機,具有唯一的入口和出口。組件可大可小。一
個較大的組件可以由多個較小的組件組裝而成,我們說大組件包含小組件。舉個簡單的例
子。組件A實現將兩個數相加的加法功能,組件B實現將兩個數相乘的乘法功能,組件C包含
了(或稱組合了)組件A和組件B,可以實現加法和乘法兩項功能。再舉一個例子。組件A對
一個由數字0/1組成的串取反,即將所有的0改寫成1,將所有的1改寫成0。組件B將一個0/
1串取逆,即反向寫這個串。組件C包含組件A和組件B,可以實現功能A和功能B的複合,即
按順序先實現功能A(取反),然後實現功能B(取逆)。這樣一來,組件C就對一個0/1串
實現了先取反再取逆的功能。注意這兩個例子差別的細微之處:前者爲功能的組合,後者
爲功能的複合。因爲組件都有唯一的入口和出口,要實現組件組合或複合的功能是比較容
易的。對於第一個例子,組合組件只須從其入口參數中知道外界要求的是加法還是乘法,
即可方便地轉向調用相應的子組件。對於第二個例子,複合組件可以使用管道技術,將一
個子組件的輸出結果定向到另一個子組件的入口來實現功能的複合。當然還可以使用其它
實現技術,我們這裏主要關注概念,而非具體實現。
一種更高級的重用機制是框架重用。框架(Framework)是由槽或稱空穴(Slot /Cavity/
Hole)通過管道或稱通道(Pipeline/Channel)按照一定的順序連接起來構成的實體。框
架中槽的概念類似於面向對象程序設計中的虛類,起着佔位的作用,是原型,是虛擬實體
,有待於框架在使用過程中與特定的組件結合而實現實體化。但槽的接口是規定好了的,
槽與槽之間通過管道相連接。這種連接是靜態連接,區別於後面將要談到的動態連接。一
個槽可以與多個其它的槽相連接。每個槽在實體化過程中都要與一個特定的組件相結合,
結合了組件的槽稱爲角色。當一個框架中的所有的槽都結合了相應的組件之後,這樣的框
架稱爲滿的。在此之前的框架是不滿的或是空的。因爲同樣的組件可以結合到不同的框架
中的不同槽上,從而充當不同的角色,這就是組件的多態性。一個框架形成了特定的上下
文(Context),同樣的組件在這個上下文中的語義與它在另外的上下文中的語義可能大相
徑庭,即組件的角色可以完全不同。這就是所謂一詞多義,多態性其實就是一詞多義。
這裏有一個問題:一個槽可以連接多個其它的槽,而且一個槽必須和一個組件相結合,而
組件只有一個入口和一個出口,這個問題如何解決呢?這涉及靜態結構與動態結構的關係
問題。框架中槽之間的連接——管道是屬於靜態連接,與時間無關,一旦槽結合了組件並
運行起來之後,組件之間的連接就屬於動態連接,與時間緊密相關。在每個特定的時刻,
一個組件只跟另外的唯一的組件保持連接,接受其輸入輸出。這有點像操作系統的分時概
念,從一段時間看,操作系統不間斷地運行了多個不同的進程,但在每一個特定的時刻,
它只是在運行唯一的一個進程,操作系統是在多個進程間不停地切換。框架也是一樣。在
運行時,框架的管道好似一個個開關,不停地切換到需要進行通訊的嵌在框架的槽上的組
件之間,爲它們建立實時的連接通道。這就是框架的運行時結構,即動態結構,可以看到
它是十分複雜的。
我們之所以要求組件只有一個入口和出口,而不是像傳統上那樣允許組件有多個參數,主
要是因爲我們設想框架和組件是獨立開發的,框架中只具有比較原始的槽,它的主要作用
是構造好槽之間的連接——管道,這屬於基礎設施建設。在結合組件之前,框架根本不知
道組件的接口,甚至就連將要結合什麼組件也是未知的。所以只能要求組件具有一致的接
口,我們這裏使用唯一的入口與出口來實現,也就是要求組件的輸入和輸出都是一個字符
串,退化的情形下可以是空串。至於字符串的內容如何解釋,比如一個輸入串可能打包了
多個必需的參數,那是屬於語義問題,由組件負責處理,框架只是負責將這些字符串從一
個槽傳遞到另一個槽,這經由管道完成。而組件具有唯一的入口與出口也保證了組件的獨
立開發與測試能力,在與框架的槽結合時容易做到即插即用。
框架和組件都是可定製的,可重用的實體,它們可以分別地獨立地開發和調試。其實,框
架本身可設計成組件的形式,也具有一個入口和一個出口,這樣就可作爲一個完整的組件
嵌套到更大的框架內使用。一個系統可以由若干個大的框架組成,大框架下嵌套着小框架
,諸如此類,形成有序的層次結構,框架的槽上結合着組件。總之,系統就是通過框架把
組件結合在一起形成的有機整體,這也符合人對自然的直觀認知。
以上是對框架的粗略的描述,實現起來需要解決一些技術細節上的問題。比如連接框架中
各槽之間的管道如何實現的問題,可以使用消息傳遞機制,而且要考慮到性能,容錯,同
步死鎖,實現的複雜程度等等,需要專門的篇幅討論,這裏就略去了。
上面涉及到的主要是系統的功能分解與結構分解的問題,下面簡要提及另外兩個矛盾。
我們知道,凡是具有一定規模的較爲複雜的系統,都不是少數幾個人能夠完成的,這就涉
及到多人協作的問題。人數越多,花在人與人之間交流和溝通上的時間與精力就越多,相
比於人數較少時,每個人的平均效率是下降了。這好比是一個集合,分解成若干個較小的
子集合,這些子集合的並要覆蓋原來的集合,但子集合之間互有重疊。分解的越細緻,子
集合的數量越多,相互之間的重疊就越多,最後所有子集合的面積加起來,可能會達到原
來集合的若干倍。軟件開發中多人合作的情形與此類似。當有上百人合作一個項目時,大
量的工作花在了組織協調上面,總的工作量可能多花了好幾倍。在一個大系統中,很多人
只是負責系統的某個很小的部分,以致於對系統的全局沒有什麼概念。這就是前面提到的
系統的全局性與個人的視野局部性的矛盾。即便對系統的總體設計師也有一個全局和局部
的關係如何把握的問題。心理學研究表明,個人能夠同時處理的任務數大致是7±2個。也
就是說,人的視野是有限的,難以同時顧及10個以上的個體,只能顧及到視野範圍內很少
的幾個個體,其它的就視而不見了。但是人作爲高級動物具有抽象能力,能夠從高處看問
題,所謂站得高看得遠。將系統分解成層層嵌套的層次結構(Hierarchy)正是運用了這種
抽象能力解決系統的全局性與視野有限性矛盾的方法。框架式結構分解方法就是應用了層
次結構分解。
以上談到的功能分解與結構分解以及全局結構與局部結構都是屬於靜態結構的部分,是空
間結構的層面,而系統運行時的結構還要把時間維度加進來,是時空結構,屬於動態結構
的層面。實際上,系統的動態結構要複雜得多。從宏觀上看,信息從系統的一部分流向另
一部分,更具體地說,是數據流和指令流從一個框架流向另外的框架,在框架內部是從一
個組件流向其他的組件,其中有很多數據與指令的流動是隨機觸發的,事先難以預測。當
系統的複雜程度達到一定規模時,甚至會產生混沌(Chaos)現象。混沌現象的出現從某種
程度上預示了人類認識世界和改造世界能力的侷限性。因爲混沌是對初始條件極端敏感和
不可預測的代名詞,它反映的是客觀世界的無限複雜與人類認知的有限至多是可列無窮之
間的矛盾。實際上,人類是根據自身感知器官獲得的有限數據建構起整個世界模型的,可
以想象且完全符合邏輯的是存在另外的生命形式,他們的感知器官與我們的並不一致,他
們能夠感知到我們無法感知的東西,那麼他們所理解和建構的世界模型就有可能與我們的
世界大相徑庭。現代物理學中的超弦理論預示了多維時空存在的現實可能性,注意這裏的
多維時空並非只是傳統上數學家腦子裏構造的抽象概念,而是現實生活中的客觀存在。那
麼我們完全有理由設想存在那樣的生物,他們能夠感知更多維的時空,他們感知的世界景
象我們永遠也感受不到。甚至於他們與我們生活在完全正交的時空中,彼此無法感知對方
的存在。這並非無稽之談,而是完全可能的。
以上的討論似乎有點玄學的味道,但是“玄之又玄,衆妙之門”。一門科學,如果不能夠
上升到哲學的高度,那它就只是停留在工匠的層次,就算是工匠也不會是好的工匠,無法
實現超越自身,做到融會貫通。
說到底,所有的程序設計和軟件開發模式都是面向人的,是爲了方便人理解和溝通的,因
爲對於機器來說,所有的程序都要編譯成機器代碼,就是機器認識的01串。我們尋找的是
那種面向人的,簡單的,直觀的,便於人理解和交流的程序設計和軟件開發模式,基於框
架和組件的模式無疑是一個好的嘗試,作爲面向對象模式的改進和發展,現在也已開始流
行。當然,這種基於框架和組件的模式仍顯得過於機械和呆板,不夠智能化,沒有把人工
神經網絡等經驗和成果包括進來。可以預期,下一代的程序設計和軟件開發模式將會應用
神經網絡,遺傳算法,機器學習理論等等研究成果,使軟件的設計開發更加智能化,自動
化,從而加快實現程序完全自動生成的一天早日到來。

--

※ 修改:·dych 於 Dec 24 08:02:28 2002 修改本文·[FROM: 141.225.225.136]
※ 來源:·BBS 水木清華站 smth.org·[FROM: 141.225.225.136]
發佈了28 篇原創文章 · 獲贊 1 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章