“……所以,我們希望使得軟件也可以像硬件一樣——將實現同一功能的電路放在一起,做成集成電路并封裝,只留下定義清晰的引腳作為接口——這樣在需求相似
的地方,只要使用這個已經制造好的芯片就可以了,而無需再次設計電路。這就是復用的思想,這樣可以極大的提高生產效率和技術的積累。正因為有了IC,硬件
發展的水平已經遠遠的將軟件發展的水平甩在了身后,目前軟件發展還只是進行到模塊化而已,而就我所知系統級規模的復用也還是在發展階段……還遠沒有到達軟
件IC的地步……總之你要了解自己所處于的技術浪潮中,這樣才可以更好的把握自己……”不知道兩個人在聊什么,不知不覺就又聊到了編程這個話題。“同時軟
件業可以像其它行業學習的東西很多,比如像硬件學習封裝和復用,像建筑業學習模式,像心理學和工業設計學學習UI設計……等等等等,總之要心態開放,兼容
并包,虛心學習,不要以為自己有多么了不起——就各行各業的發展時間來看,軟件業吃的飯還沒有一些傳統行業吃的鹽多……”老C開始給小P狂噴。兩個人下午
上完課也沒有什么事情,干脆把椅子拉在一起狂諞起來。
“嗯,我覺得你說的有些道理,那么我們的編程語言是如何對模塊化進行支持的呢?”小P覺得自己的捧場很重要,如果沒有自己說“然后呢……其他呢……”等
等,老C不會狂噴這么多有意思的話題,所以他很是恰當的在旁邊煽風。“一開始的時候沒有直接的模塊化的支持,”老C道,“后來人們根據實際需求總結出來一
些使用語言的方法,形成一定的業內規范,將語言形成的代碼組織得更容易形成模塊。比如我們在使用C語言時,將模塊的接口聲明到.h文件,內部實現放在.c
文件并且用static聲明,這樣就提供了某些封裝的方法——但不是強制的,如果你違反了這些規定,語言本身是拿你沒有辦法的——這個時候就需要從行政上
動腦筋……比如扣除一部分你的勞動所得等等,哈哈。”老C笑道,“但是這種約定只是在坊間流傳,基本上不會在介紹語言的書籍或者課本上出現——因為這些是
工程經驗,而理論雖然在理論上講與實踐沒有什么區別,但是從實踐的觀點看,結論正好相反——因此企業不得不花費一些時間教會新手和菜鳥遵守某些坊間流傳的
規矩和約定。”
“哦?也就是說如果我們畢業就算找到工作,也還是不能馬上就給企業帶來效益的?”小P問。
“嗯,是的。所以雖然企業內部急需要人才,但是應屆畢業生工作還是挺難找的,因為很多企業不想花費一些培訓和引導的成本,所以就在社會上尋找有經驗的人。
但是有經驗的人哪里這么好找啊……于是就出現了矛盾——一方面好多人找不到工作,另一方面企業又需要人……”老C道。
“哦?那么沒有什么好的解決方法嗎?”小P問。
“我覺得也有辦法,學校尤其是一類院校可以從企業吸收一些高級人才,充當一線教師和導師……但是這里面牽扯了方方面面的利益,實現起來比較困難。同時由于
學校的學術界有固步自封的傾向,一味追求理論上的高新,基本上不會考慮實現上的問題,導致大量水文的出現,造成一定程度上畢業生質量的下降。我覺得如果一
個人可以很好的將某種理論以實際的方法實現,應當也頒發學歷和學位的——因為這樣學術研究才會真正變為生產力——要知道數字信號處理在FFT變換出來之前
也只是理論上的玩具而已,但是隨著FFT的被發現,信息技術才有了突飛猛進的發展啊……”老C感概道,“呵呵,一下子說的遠了,跑題,跑題……”他咋咋
嘴,嘆了一口氣,“題外話就不多說了,我們再來看看隨著科技的發展,語言又對我們的模塊化編程提供了哪些支持吧。”
“哦,然后呢?”小P問。
“然后隨著人們經驗的增加和積累,發現在語言層面對模塊這個概念提供支持是很好很強大的想法,至于怎么實現模塊化,見仁見智,相互PK,總之我們看到的結
論是經過在市場上的殘酷廝殺,面向對象理論發展了起來。”老C道,“其實我們用非面向對象的語言也可以實現面向對象的某些思想,比如可以在C中用結構體+
對結構體操作的函數的方式構造我們的模塊,但——你也看到了——到底沒有語言上直接支持來的方便和輕松。”老C撓撓頭,“因為人們開始接受面向對象的語
言,如何對設計過程和設計所使用的模型進行描述又有了新的爭議……”
“哦?什么是設計模型?”小P問。
“……簡單的說,我們在蓋房子的時候一般都會先簡單的畫出一個草圖吧,也叫藍圖,blue
print的東東,然后再進行詳細的計算和設計……沒有見過沒有圖紙就直接上的,這樣既不安全,出了問題也比較難以修改,這個就是草圖和藍圖的作用,而草
圖和藍圖描述的就是房子的模型——因為房子只出現在概念中,還沒有被實際蓋出來。”老C覺的要向這個無知青年解釋清楚還是比較累人的,“又比如我們要進行
一個飛機場空中管制和航班管理的軟件,你會怎么做?”
“呵呵,依我現在的水平——不要想,就是我的做法……”小P答道。
“……也是……哈哈,我覺得你應當先去買一套飛機場的玩具,然后模擬幾次飛機的起降過程,并人為的制造一些障礙,比如飛機晚點,天氣不好等等,來熟悉你即將碰到的問題并想辦法解決之。這就是建模的過程,體現了一些模型的重要性。”老C笑道。
“哦,我明白了,”小P高興的說道,“就是說在實際實現前,概念上和理論上的對問題進行仿真和建模,并用某種方式表達出來,這樣對開發過程很有益處……”
“沒錯沒錯。”老C同意,“就像流程圖這個我們在結構化編程時經常使用的建模工具,在面向對象時代也有類似的,但是更強大的工具來支持我們建模。同時這種
工具不但可以在外部對問題進行描述,對問題域進行記錄,而且還可以記錄解決問題的方案,程序的結構等解決域的內容。”他想了想,又說道,“在歷史上有多種
這樣的符號和圖形系統——畢竟一圖頂千言,哦,不,是正確的清晰的一圖才可以頂千言——最后經過努力這些圖形和符號都統一為一種符號和表述方式……就像電
路符號是實際電路的建模一樣,如果同時存在7、8種電阻符號,那樣引起的混亂有可能比沒有建模還嚴重呢。”
“喔?這么說其實建模的工具就是一些用來描述問題和軟件結構的圖形和符號?就像我在電路課程中學習的電阻、電感和電容符號那樣?”小P問。
“沒錯!這種被統一后的符號集和圖形集被稱為UML,近來還在里面加入了一些在符號間找來找去的腳本語言……”老C接著道,“所謂UML,就是Unified Modeling Language的簡稱,從Unified這個詞,你就可以看出它發展的歷史。”
“哦,原來名字的來歷是這樣啊。”小P道。
“是啊,無論怎么樣,統一和標準是我們的需求,只有用統一的標準的符號我們才可以更好的交流。一個反面的例子是我們上數字電路里面的與門、非門、與非門和
或門等等的邏輯符號,國家標準與業界流行的標準就不一樣,導致學生在畢業的時候可能看不懂行業內的電路圖——就事實而論,我們大部分的電路模塊產品和芯片
的說明手冊還是歐美的居多——這樣即加重了企業負擔,可能需要再花一部分精力來培訓新人,也增加了學生的負擔——為了在畢業的時候增加些許競爭力,不得不
學習兩套符號系統。總之我覺得這個事情還是比較腦殘的,讓我想到窄軌鐵路……”老C借機發泄了一下從畢業就開始累積的郁悶。
“呵呵……”小P嘴上打著哈哈,心想,不就是多記幾個框框嘛,對自己影響不是很大啊,“消消氣,我們還是來說說UML本身吧。”小P道。
“嗯……我覺得首先我們得先明確幾個概念——要知道概念是比技巧更重要的東西——為了明確這些概念,我們最好先來談論一些哲學問題。”老C道,“首先來UML的陰與陽。”
“陰與陽?”小P槑。
“對,呵呵,無極生太極,太極生兩儀,兩儀生八卦……”老C開始轉文。
“八卦?我覺得隔壁的行司就比較八卦……”小P小聲說道。
“哈哈,這里說的陰與陽,是指UML模型中class與object概念的對偶,靜態模型與動態模型的區分。”老C道,“這些都是不同的概念,我們現在來仔細說說。”
“哦?是嗎?那太好了。”小P道。
“首先我們來區分class與object的概念,什么是class?什么是object?我們先在概念上討論一下,然后再看看在C語言里是怎么一回事。
首先講概念,我們來打個簡單的比方。”因為要開始長篇大論,老C把自己的茶杯端到手里,“比如你在一村閑逛,看到一只小狗在樹下面小便,你會說‘狗撒尿
’……”
“哦,這個例子顯得……每下愈況……”小P道。
“呵呵,你總結的很好很強大……”老C突然有了伯牙遇子期的感慨,“話說高山……哦,不,狗撒尿,在這里,狗就是類的概念。”老C道,“因為所有的狗,無
論什么品種,都會撒尿,因此你會建立一個‘狗’的概念,這個‘狗’只是存在于理性世界當中,并不是真實存在的,只是一種模型而已,這就是對類這個概念的簡
單理解。如果你知道這條狗叫旺財,你會說‘旺財撒尿’,那么這里‘旺財’就是‘狗’這個類的一個對象,因為‘旺財’是‘狗’這個概念的實體。”
“喔?這樣說來就是概念與實體的區別了?”小P問。
“嗯,可以先簡單的這樣理解。”老C說,“而‘撒尿’就是‘狗’這個類所具有的‘操作’,就是說只要是‘狗’,一定會‘撒尿’。”
“哦,有點需要理解力了。”小P道。
“呵呵,可以這樣理解,‘狗’與‘撒尿’這兩個都是概念,生活在理性的世界,而‘旺財’和‘旺財的撒尿動作’是實體,生活在現實世界。”老C解釋道,“但是理性世界的概念在實例化之前不會有任何作用……因為它們本身都是概念而已。”
“太抽象了,來點具體的吧。”小P埋怨。
“呵呵,形而上者謂之道,形而下者謂之器,先道而后器者,幾稀!”老C又轉文,“可以可以,我們在C++中舉個簡單的例子。”他又指揮小P拉過來白板并擦干凈,寫下如下代碼。
class Dog
{
public:
Dog(const string& name) : name_(name) {}
piss() {}
private:
string name_;
};
int main()
{
Dog wangCai("Wang Cai");
wangCai.piss();
return 0;
}
“看,我們的Dog類,在還沒有生成wangCai對象前,并沒有什么實際的作用,它只是記錄了一些類型和函數的信息而已。然而一旦生成了wangCai
對象,那么在實際內存中——無所謂是在棧還是堆——都占有了一席之地,而這個對象的行為都會依照我們class內部的設定而進行。”老C道。
“唔,這么一說,我倒是理解了很多。”小P道。
“呵呵,還是要在實際編程中多體會和領悟。”老C說道。“現在我們來說說class和object如何在UML中表示,沒有什么難的,就像電阻、電感或者
電容一樣,只是一種記號。”老C道,并在白板上畫了兩個框框,“不同的訪問等級分別用+,#,和-表示,你可以google一下class
diagram,查找一些具體的信息。”他接著說道,“有了class和object的表示方法,我們需要了解一下如何表示它們之間的關系。”
“哦?”小P一副疑惑的樣子。
“因為我們的對象都不可能是孤島,對象之間需要相互協作才可以完成一些功能。形而下的對象之間如何發生了相互的聯系,那么在形而上的類之間就會塑模出各種
關系。”老C說道,“我們先來說說最簡單的也是最寬泛的一種關系——對于類來說叫association,對于對象來說叫link……你要習慣這種概念體
系,因為在UML中,形而上和形而下被區分的很明顯,你要理解這種概念上的對偶。”
“那么什么叫做association呢?”小P問道。
“嗯,只要有物理上或者概念上的關聯,都可以建模為類之間的association,或者對象之間的link。”老C回答,“同樣我們可以舉例說明一下。
比如我們選課,你選擇了《數字信號處理》、《數理統計》和《現代控制理論》,那么你就和這些課程之間發生一些link,因為你是對象,而這些課程也是對
象;我選擇了《計算機通信原理》,《數理統計》和《現代測控原理》那么我這個對象和這些課程對象之間就發生了一些link——上升到理性世界,就是形而上
的世界,那就是Person這個類與Course這個類之間發生了association。”
“哦?是這樣啊……”小P想了想,“那么怎么樣用association表示link的數量呢?因為已經抽象到另一個層次中……”
“呵呵,沒有關系,我們可以用multiplicity來表示,比如這個學期我們每個人可以最多選5門,最少選3門課,可以在class
diagram中用multiplicity來這樣表示……”老C說著畫了一個圖,“你先理解到這里就夠了,因為UML是一個理論性很強的東東,沒有必要
一下子就深入進去,這樣反而無法學好。我們先一個一個慢慢來,由淺入深,由此及彼。”
“嗯,你說的有些道理。”小P道。
“先在我們只要知道class之間有association就可以了,至于這種association具體到什么地步,那是下一步的事情。所謂建模是見仁
見智的事情,除非重大錯誤,否則你總可以認為你這樣建模是對的,因為你觀察問題的角度就是這樣……”老C道,“我們現階段就只要先搞清楚有幾個class
存在關系就行了。”
“呵呵,好的。”小P心想還沒有人教他這樣不求甚解的學習。
Link
“下來我們需要掌握sequence diagram,”老C道,“關于UML,有3中模型,分別是class model,state
model和interaction model,前一個class
model是靜態模型,后兩個是動態模型,這是UML中除形而上和形而下外又一對陰陽。”他喝了一口茶,“我們先把state
model放一邊,先學習一下interaction modle中的sequence
diagram。而且同樣也不要太深入,只要先了解一些夠我們用的部分就行了。”說罷他在白板上先寫下可見性三個大字。
可見性
“不是要說sequence diagram嗎?”小P不解的問。
“哦,sequence diagram主要是描述對象間是如何交換信息的,在此之前我們需要簡單的說說對象間交換信息的方式。”老C回答,“否則可能你對message這個概念的理解會困難一些。”他接著說,“你能告訴我兩個對象之間怎么傳遞信息嗎?”
“哦,我想想……”小P想了一回,“如果對象a需要對象b的信息,那么對象a可以調用對象b的提取信息的成員函數……”
“沒錯,這是一個辦法,”老C點頭,“如果我們把對象想象為一個一個的小島,它們之間需要通過交換信息來共同解決問題,那么你可以想象message就是
它們之間往來的小船,這些小船攜帶了需要交互的信息。比如a島需要b島的信息,或者它需要將信息發送到b島,作為活動發起人,它需要b島提供船只,然后將
信息從船上取出,或者將信息放入船上。你先這樣理解,信息的接受和發送都是被動的,如果a是發起者,那么它就需要b提供交通工具——因為你現在碰到的都是
被動類,等我們遇到了主動類,再來升級我們的認識。這樣在C++中,如果對象a需要向對象b發送一個消息,那么對象b需要提供一個接口;具體來說就是a調
用了b的成員函數。”
“哦,那我就先這樣理解著。”小P回答。
“是啊,因為一步到位的很正確和深刻的認識這個問題也不現實,我們需要在不斷的實踐中迭代的修正我們的觀念。”老C道,“現在我們來看看,如果對象a需要調用對象b的函數,那么對象b必須對對象a來說是可見的,你說說在C++中怎么樣才具有這種可見性呢?”
“唔……好像對象b要是對象a的一個成員變量?”小P不是很確定。
“嗯,只是一種情況。”老C回答,“如果對象b對于對象a可見,可能存在以下幾種情況。”說著他在白板的可見性幾個字下面又增加了幾行。
可見性
1. b 在 全局范圍內。
2. b 是a的成員變量。
3. a有一個指向b的指針(或引用),這個指針(或引用)被正確的初始化。
4. a的成員函數含有b的指針或引用的參數。
5. b的定義在a定義的外層。
“看,雖然在模型中都由a發送message給b代所塑模,但具體實現上我們可以有至少這么多的方案供選擇。”老C說,“不要狹隘的理解message,
無非就是信息交換而已。”他想了想,“為了保持你的好奇心和進取心,我再給你簡單說說當兩個對象不可見時它們怎么交換信息……”
“哦?這樣它們也可以交換信息?”小P追問。
“這時C++語言沒有提供直接的幫助,我們需要借助外力。如果我們使用類庫,可以用boost的signal/slot機制,也可以用Qt的signal
/slot機制;如果我們在windows下編程,可以借助windows操作系統的消息并借用MFC的消息映射機制;如果這些都不可用,我們還可以自己
依照command模式和observe模式設計一套機制來自己使用……這些話題我們以后一定可以討論到,現在就先不要著急啦。”老C吊起了小P的胃口,
但是又不再繼續下去。
“是嗎?”小P問道,心想自己需要學習的地方還挺多的。
“好,現在我們就具體看看sequence diagram。”老C說道。說著他讓小P打開電腦,照著AppleGame的代碼在白板上畫出了如下圖形。
AppleGame
“我來解釋一下。”老C先指著class diagram
AppleGame說道,“在這里我們只要先知道AppleGame類與ChildList類有關聯就可以了,至于具體是什么關聯,我們以后再說。”然后
他解釋道,“由于我已經知道這兩個class的成員函數了,為了省事就直接寫在里面,其實更合理的做法是先不要在這里寫需要的成員函數,而是應當在有了
class diagram后馬上去建模sequence diagram,根據解決問題的需要再回頭給class
中添加具體的成員函數。”看到小P看得聚精會神,他就停了一會兒,喝了一口水,等小P先消化消化。
“……嗯,然后呢?”幾分鐘后,小P問道。
“sequence
diagram表示了對象間數據交換的順序和過程,你可以在每個message上看到標注的數字,那表示順序。”老C接著說道,“每個對象下面垂直的虛線
叫life
ine,表示對象的生存期;虛線上的長條矩形叫做activation,表示對象是否活躍,你就認為是函數的執行期,activation之間可以重疊;
水平的實線實心箭頭表示同步消息,關于同步消息和異步消息我們以后再討論,你現在全部使用同步消息就可以了,指向對象自己的消息表示調用自己的函數;虛線
表示返回消息,你可以理解為返回值;中間的方框叫combined fragments,包括alternatives, options 和
loops。你可以根據我們已經有的代碼體會體會sequence
diagram的用法。”他想了想,“對了,關于圖的名稱也有要求,sequence
diagram要求以sd開頭,后面是所描述場景的概要說明,比如我們這里的sd PlayAppleGame。”
“哦,我學習學習。有什么線索沒有?”小P追問。
“嗯,關于UML工具有很多,跨平臺,GPL的也不少,我試用了一些,感覺visual paradigm和magic
draw還不錯,這兩個都有community版本的,可以供我們學習和進行非商業活動用。你還可以登陸到www.umlchina.com,那里也有一
些很不錯的資料和書籍介紹。但是根據我的經驗,UML還是要多用,而且不要一次學習的過于深入為好,因為UML的語義很豐富且理論性比較深一些,而且同樣
的事情可能有不同的圖形都可以描述,所以最好根據需要,一點一點的學習,邊學邊用最好。”老C說道。
“哦,是啊。”小P點點頭。
“UML是建模工具,不是編程工具。模型需要對實際的事物進行合理的剪裁和取舍,注意模型的清晰性比信息的完備性更重要,如果不論青紅皂白的將所有信息一
股腦全部放在模型上,那樣圖形看起來會很恐怖的。”老C接著解釋,“所以不要要求模型完全反應細節信息,只要在大方向上對就可以了。同時你還要了解模型所
要描述的問題規模,如果是一個大型的交易系統,按照我繪出的sequence
diagram的詳細程度,那是根本不可能的。在描述這樣的系統時,可以省略足夠的細節,可以在框架結構的規模上表現清楚就可以了。”老C道。
“是么?看來我還需要在實踐中學習啊。”小P說道,“看來以后你還要多給我說說這方面的道理。”
“呵呵,好啊。反正國慶假期也快到了,如果你沒有什么事情的話就繼續完善我們的sd PlayAppleGame如何?將List類也加入其中。” 老C問道。
“好啊好啊。”小P道,“我可以趁沒有出去玩的時候自己畫畫試試。”他想了想,“但是如果有什么不會的我可要打你的電話啊。”
“當然可以,”老C說道,“如果沒有人接那是我在外面沒有聽見,你最好晚上打。”
(看看小P如何完成sd PlayAppleGame)
注:
本章中的許多內容都穿越啦。Visual Paradigm在2003年還沒有出來這一套UML2.1標準的UML工具,而老C說的在class
model中導航的OCL語言也是在2006年左右才出來的。本章中sequence
diagram中使用的很多符號都是UML2.0標準的,這在2003年根本沒有……