編程習俗和設計模式

03-31-2016, 6th edition

04-10-2013, 5th edition

09-21-2012, 4th edition

08-28-2012, 3rd edition

05-19-2012, 2nd edition

10-05-2011, version 1.0

 

在進入正題之前,我請大家看下面這張圖片。學建築的朋友給我講到說古希臘三大柱式:

 

 

如果不是有人告訴我,我可能永遠也不知道建築學院底下那柱子是愛奧尼克式的⋯

 

編程習俗的話,也需要有人點明出來。本人在接觸編程相當久後,才深刻反思“如何寫程序”這個問題。

人們似乎有着這樣的感覺,就是編程是無國界的,這個論斷不準確。首先,所有的編程符號大都是拉丁字母,從代碼到僞代碼的角度來講,西方國家的人更容易理解。 這個理由太牽強?那我就具體道來,每一門程序語言的community都有自己的convention(習俗,所謂習俗就是約定俗成,人盡皆知的)。比如說當說到set, 這表示有這麼一個collection,他們的元素沒有重複的;當說到List, 它表示這個collection的元素新元素會經過一定方法append到老元素之後。一個類是另一個類的factory, 就是說它能以某種方式生產出其關聯類。設計模式爲叫那個名字,observer爲什麼也叫publish-subscribe, strategy爲什麼也叫policy,本身的意義和類比對於講英語的人是make sense的,可是對於非英語母語的我們來說,他就是一個記憶的名稱而已,感悟自然不夠深刻。再比如一些Community,比如Java community,寫interface讓你儘可能用形容詞(作名詞), Runnable, Collidable, Collectable, 如果想不起來這些英語單詞,怎麼做到”readable“?

還有一些習俗,比如.NET和ActionScript寫interface喜歡加一個“I”爲前綴;  微軟程序員喜歡匈牙利(其某個程序是匈牙利人)命名法則,每一個命名的首字母提示他的類型。再比如SFX的前綴常常表示音效文件sound effects。再比如一系列的naming convention。

 

舉幾個設計模式的例子。我們說,“開汽車”的時候,我們實際上是在動方向盤,而真正讓車子動起來的是發動機,讓車子跑的是輪子。但是我們看不到發動機,也不知道發動機怎麼工作的,我們做的, 如果描述成一個method,可以是:

車{
    左轉() {
        方向盤.左轉();
    }
}

(方向盤左轉的implemenation中,可能又調用了調用了其他元件,我們就不深究了)

這個就是delegation的概念。

 

雖然說繼承是面向對象很重要的特徵,但實際中composite還是首選,其意思就是“包含”。所以當寫程序的時候,你要先考慮一下你的寫法是否make sense. 比如汽車可以放CD, 你會寫汽車繼承了CD player, 同時又多了一些輪子什麼的麼?或者汽車繼承了空調,同時有幾個參數是座位什麼的?這些顯然沒那麼準確,要考慮有沒有“is a"這種relationship,實際中情況更復雜。

 

比如說,有人想租房,有人出租房,有人中介。你想租房找中介,中介給你介紹。這個模式叫做mediator, 中間人,你是不知道到底那個人擁有那個房子的。同時,另外一個人也想租那一幢,中介告訴他有人租了,他灰溜溜走了。他也不知到是你租的。這就是一個很好的封裝性。

 

所謂設計模式也是從建築學中借來的概念。你要蓋大樓,每一層怎麼蓋,每一戶怎麼蓋,每一間怎麼蓋,電線怎麼走,插頭放哪裏,插頭什麼形狀。寫程序也是一樣。

 其實對於Software Engineering來講,沒有人是因爲腦子不夠用,我們要知道的是更多的習俗和經驗,

 

如果說編程分爲面向過程和麪向對象(也有其他的paradigm),其實不少人不屬於二者中的任何一種。因爲在課堂上沒有人告訴你、即便有——你也無法從言談中瞭解,到底什麼是面向過程的從思維到實施方式,什麼是面向對象的思維到實施方式。這是國內和國際計算機教學的一個普遍問題。做爲計算機專業的學生,把代碼寫好是沒有什麼錯的。工程能力和科研能力是不矛盾的,相反,傑出的科研團隊往往有具有明星級別的工程師。

 

用Java不代表你在面向對象,用C也不代表是在面向過程。編程的理念,這些屬於“心法”,到底用 system.out還是printf的招式不重要,20年後用什麼語言誰也不知道,但是20年後設計模式是不會變的,就好像幾千年來建築模式沒有怎麼變。

 

舉例一些geek的習慣,比如用四個空格代替一個 tab, 這樣你的代碼在不同的編輯器裏顯示的比較一樣,粘貼來粘貼去直接可以用的。想想國內論壇上90%的代碼,直接copy/paste是沒法工作的,即使在 csdn, pudn找到的資源很多也是不能用的。(這也有一個弊端,比如你在寫make file或者寫 script的時候,就一定需要tab了)

"All good writers- including those who write software- know that a piece of work isn't good until it's been rewritten."

 

 

 

9.21.2012 Started writing... 

 

 

 

當我們談到程序設計的時候,就沒有渭涇分明的錯與對,只有對於某個具體case的相對適用性好與不好~

 

 

 

Composite,有的時候爲了滿足接口的一致性(uniform),就可能引入不確定性(如類別)和冗餘信息。但如果區分每個個體,又會帶來遍歷(traverse)函數的不便。

 

 

 

State,到底誰決定狀態的轉換,每個狀態自己還是另有其他class還是根據一個table?如果是自己的話那coupling就不loose了;外部class的話flexibility又下降,一旦添加新的state,所有的logic都需要變;如果是由外部table決定的話,那程序的可讀性下降。

 

 

 

說到observer,到底是用push model還是pull model呢。前者,subject一旦有更新就把詳細的數據更新訊息告訴observer(們),不管他們需要需要想不想要。而pull model,只告訴最小的更新訊息,哪個observer之後要用再自己索取。前者假定subject和observer互相瞭解,這樣程序的複用性(reusability)下降,而後者雖然精簡,但是會低效,因爲observer需要獨自查明確定到底subject發生了什麼改變。

 

 

 

再比如,effciency和coupling的tradeoff,需要高效,那類之間的聯繫就會更具體和確定,而這樣相對獨立性和複用性就下降。很多時候是傳一個類作爲參數,還是傳若干個變量呢?前者更直接,而兩個類的關係必然會緊密。而傳參數的話,method會更general,但還要對結果進行一定加工。

 

 

 

需要command更智能,那它就需要知道了解的越多,這樣他的reference就自然多了,也就越針對某個個體,而不是general的。。維護(maintenance)起來也就麻煩。

 

 

 

有的時候subclassing和複雜的structure本身過於繁複也會讓人望而卻步,不夠直觀,可讀性下降。到底什麼纔是subclassing的度呢。用template class還是subclassing呢? 前者可以高效,後者可能更make sense。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章