誰更穩(wěn)定?

前兩天芯杀,有人專程跑到我的文章《類與封裝》留言端考,說數(shù)據結構更加抽象,更加穩(wěn)定揭厚,因而OO封裝make sense却特。為了證明其觀點,還專門引用了Fred Brooks在《人月神話》里的敘述:

Show me your flowcharts, and conceal your tables, and I shall continue to be mystified; show me your tables and I won't usually need your flowcharts: they'll be obvious.
-- Fred Brooks, "The Mythical Man Month", chapter 9

這位朋友的觀點其實并不鮮見:我已經見過太多的反OO碼農筛圆,以此為證據裂明,來支持其“OO無用,封裝無用太援,對數(shù)據結構的直接依賴更好...”諸如此類的結論闽晦。而那位朋友更是在回復中對眾人呼吁:作為程序員扳碍,不要學什么OOSOLID……

而每次聽到這類宗教戰(zhàn)爭般的言論仙蛉,我都會一邊苦笑笋敞,一邊心里嘀咕:這些人真正負責過復雜一點的系統(tǒng)開發(fā),交付和維護么荠瘪?

事實上液样,強調數(shù)據結構算法更重要的觀點,我還可以舉出更多巧还。

比如Linus Torvalds一封郵件里所表達的觀點:

(*) I will, in fact, claim that the difference between a bad programmer
and a good one is whether he considers his code or his data structures
more important. Bad programmers worry about the code. Good programmers
worry about data structures and their relationships.

再比如鞭莽,在《The Art of Unix Programming》里,也表達了類似的觀點:

Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.

Even the simplest procedural logic is hard for humans to verify, but quite complex data structures are fairly easy to model and reason about. To see this, compare the expressiveness and explanatory power of a diagram of (say) a fifty-node pointer tree with a flowchart of a fifty-line program. Or, compare an array initializer expressing a conversion table with an equivalent switch statement. The difference in transparency and clarity is dramatic. See Rob Pike's Rule 5.

Data is more tractable than program logic. It follows that where you see a choice between complexity in data structures and complexity in code, choose the former. More: in evolving a design, you should actively seek ways to shift complexity from code to data.

The Unix community did not originate this insight, but a lot of Unix code displays its influence. The C language's facility at manipulating pointers, in particular, has encouraged the use of dynamically-modified reference structures at all levels of coding from the kernel upward. Simple pointer chases in such structures frequently do duties that implementations in other languages would instead have to embody in more elaborate procedures.

如果愿意麸祷,我還可以舉出更多澎怒。

我從未懷疑過這些觀點的正確性,而這也正是我的觀點阶牍。

首先喷面,所有這些被引用的觀點,其實都是在強調:數(shù)據的清晰性走孽。

任何一個有經驗惧辈,有sense的程序員,都會承認數(shù)據結構的重要性磕瓷。一個良好定義的數(shù)據結構以及它們之間的關系盒齿,往往比算法更清晰。

這是因為困食,一個良好的數(shù)據結構定義所要表達的概念边翁,以及概念之間的關系,是一種高度結構化的信息硕盹。而我們人類的大腦符匾,最善于理解的就是這類信息。相對于不那么結構化的瘩例,代表算法的流程圖啊胶,實體關系圖所需的智商指數(shù)要低的多。

而反過來垛贤,有了這些高度結構化的數(shù)據結構之后焰坪,我們就更容易推理和理解圍繞這些數(shù)據結構的算法。

這也正是我們在分析一個業(yè)務領域南吮,建立其領域模型時琳彩,靜態(tài)視圖:包含(概念實體)以及類與類之間的關系,對于理解一個領域至關重要的原因。

領域對象模型
領域對象模型

當然露乏,這一切碧浊,都是建立在一個良好的領域分析基礎上的。作為咨詢師瘟仿,我見過太多團隊箱锐,根本不重視數(shù)據結構的定義,完全不考慮數(shù)據結構所代表的概念劳较,也不考慮數(shù)據的內聚性驹止,只見到系統(tǒng)堆滿了隨機而凌亂的數(shù)據結構,從而讓系統(tǒng)極難理解观蜗。

這也正是為何Linus強調:糟糕的程序員更關注代碼(算法)臊恋;而優(yōu)秀的程序員更關注數(shù)據結構和它們之間的關系

數(shù)據結構定義的重要性墓捻,怎么強調都不為過抖仅。

數(shù)據結構,相對于算法砖第,不僅更清晰撤卢,在大多數(shù)情況下甚至會更穩(wěn)定

首先梧兼,我們先看一個簡單的例子放吩。如下代碼定義了一個數(shù)據結構Rectangle

struct Rectangle
{
    unsigned int height;
    unsigned int width;
};

不難發(fā)現(xiàn),這個用來表現(xiàn)矩形的數(shù)據結構羽杰,是非常清晰的渡紫。

而圍繞它的算法,相對于它的數(shù)據忽洛,卻更加不穩(wěn)定腻惠。比如,現(xiàn)在某個需求需要求它的周長欲虚,因而,我們需要提供一個算法:

unsigned int calcPerimeter(Rectangle* rect)
{
    return (rect->height + rect->width) * 2;
}

當然悔雹,也可以將算法實現(xiàn)為:

unsigned int calcPerimeter(Rectangle* rect)
{
    return rect->height * 2 + rect->width * 2;
}

或者:

unsigned int calcPerimeter(Rectangle* rect)
{
    return rect->height + rect->height + rect->width + rect->width;
}

不難看出复哆,對于同一個需求,我們可以基于同一個數(shù)據結構腌零,給出不同的算法實現(xiàn)梯找。因而,在這個例子中益涧,數(shù)據結構算法更清晰锈锤,也更穩(wěn)定。

但這是否就意味著,封裝對于Rectangle就沒有意義久免?

對于一個軟件系統(tǒng)浅辙,單純的數(shù)據結構是沒有太多意義的(除非它只是一個數(shù)據展現(xiàn)系統(tǒng))。數(shù)據結構和算法阎姥,都是為客戶的根本需要而服務记舆。沒有客戶的需要,則數(shù)據結構和算法呼巴,無論誰更清晰泽腮,更穩(wěn)定,都沒有任何意義衣赶。一個數(shù)據結構該怎么定義诊赊,一個算法該如何設計,這一切都是從客戶的需要出發(fā)府瞄,結合各種約束豪筝,程序員作出的選擇而已。

比如摘能,同樣都是矩形续崖,如果現(xiàn)在我們正在做的是一個畫圖系統(tǒng),則其數(shù)據并不必然使用widthheight來表示团搞,這時候严望,使用坐標位置,或向量來表示矩形逻恐,會是更合理的選擇像吻。

因而,盡管在不同領域里复隆,有可能都能挖掘出相同的領域概念拨匆,以及相同的領域概念間關系。但其具體數(shù)據(屬性)挽拂,卻會伴隨著不同領域的需求不同而不同惭每。

另外,即便在同一個領域亏栈,對于同樣的業(yè)務需求台腥,當定義數(shù)據結構時,往往也會由于性能绒北,空間黎侈,便利性等非功能性需求和設計約束,而作出不同的決定闷游。比如峻汉,同樣都是1..N的關系贴汪,我究竟該選擇Array還是List?如果選擇List休吠,改選單向扳埂,還是雙向?對于每個有經驗的C,C++開發(fā)者蛛碌,這都是做一個真實系統(tǒng)時經常需要考慮的問題聂喇。

我們已經知道,Linus極其重視數(shù)據結構的定義蔚携,如果我們去看Linux Kernel的設計希太,就能知道,其數(shù)據結構的選擇酝蜒,和數(shù)據間的關聯(lián)選擇誊辉,會多大程度上受到非功能因素的影響。否則亡脑,那些數(shù)據結構的定義會更加清晰堕澄,穩(wěn)定和簡單。

但你無論如何選擇霉咨,最終都是為了滿足客戶的業(yè)務需要蛙紫。

回到我們的Rectangle。從需求出發(fā)途戒,我們的系統(tǒng)存在Rectangle這個概念坑傅,那么客戶需要這個概念的真正原因是什么?是Rectangle數(shù)據結構喷斋,還是calcPerimeter內部的算法唁毒?

答案是:都不是

客戶真正需要星爪,也真正依賴的是API: unsigned int calcPerimeter(Rectangle* rect)浆西,而不是Rectangle數(shù)據結構,更不是calcPerimeter算法實現(xiàn)顽腾。

雖然數(shù)據結構算法實現(xiàn)更穩(wěn)定近零,但它再穩(wěn)定,相對于API崔泵,也依然只是一種實現(xiàn)細節(jié)秒赤。

而讓客戶向著更穩(wěn)定的方向依賴(參見《變化驅動:正交設計》),從而依賴API憎瘸,而不是直接依賴數(shù)據結構,這就是封裝的核心價值陈瘦。

封裝
封裝

而如果不進行封裝幌甘,客戶擁有訪問數(shù)據,并定義算法的自由,就會讓客戶同時依賴數(shù)據結構和算法锅风。無論你認為數(shù)據結構更不穩(wěn)定酥诽,還是算法更不穩(wěn)定,總之都會讓用戶直接依賴在不穩(wěn)定的事物上皱埠。同時肮帐,在大產品下,極易造成重復边器,這會進一步導致更嚴重的耦合(見《類與封裝》)训枢。

數(shù)據結構算法還在爭論誰更抽象,更穩(wěn)定時忘巧,API笑了恒界。

而最最重要的部分,在Grady Booch著名的《面向對象分析與設計》中砚嘴,對OOP定義的第一個要點則是:

利用對象作為面向對象編程的基本邏輯構建塊十酣,而不是利用算法

這與把Procedure看做Building Block面向過程范式际长,把Function看做Building Block函數(shù)式范式相比耸采,如果我們認為數(shù)據結構算法更穩(wěn)定是一個事實,那么毫無疑問工育,面向對象才是更加尊重這個事實的范式虾宇。

因而,從數(shù)據結構算法更穩(wěn)定出發(fā)翅娶,不僅不應該得到OO無用的結論文留,而應該恰恰相反:OO是在已有的范式中,最符合軟件問題本質的選擇竭沫。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末燥翅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜕提,更是在濱河造成了極大的恐慌森书,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谎势,死亡現(xiàn)場離奇詭異凛膏,居然都是意外死亡,警方通過查閱死者的電腦和手機脏榆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門猖毫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人须喂,你說我怎么就攤上這事吁断〕萌铮” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵仔役,是天一觀的道長掷伙。 經常有香客問我,道長又兵,這世上最難降的妖魔是什么任柜? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮沛厨,結果婚禮上宙地,老公的妹妹穿的比我還像新娘。我一直安慰自己俄烁,他們只是感情好绸栅,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著页屠,像睡著了一般粹胯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辰企,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天风纠,我揣著相機與錄音,去河邊找鬼牢贸。 笑死竹观,一個胖子當著我的面吹牛,可吹牛的內容都是我干的潜索。 我是一名探鬼主播臭增,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼竹习!你這毒婦竟也來了誊抛?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤整陌,失蹤者是張志新(化名)和其女友劉穎拗窃,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泌辫,經...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡随夸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了震放。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宾毒。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖殿遂,靈堂內的尸體忽然破棺而出伍俘,到底是詐尸還是另有隱情邪锌,我是刑警寧澤勉躺,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布癌瘾,位于F島的核電站,受9級特大地震影響饵溅,放射性物質發(fā)生泄漏妨退。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一蜕企、第九天 我趴在偏房一處隱蔽的房頂上張望咬荷。 院中可真熱鬧,春花似錦轻掩、人聲如沸幸乒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽罕扎。三九已至,卻和暖如春丐重,著一層夾襖步出監(jiān)牢的瞬間腔召,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工扮惦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留臀蛛,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓崖蜜,卻偏偏與公主長得像浊仆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子豫领,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內容

  • 文章作者:Tyan博客:noahsnail.com | CSDN | 簡書 翻譯論文匯總:https://gith...
    SnailTyan閱讀 9,896評論 0 8
  • 常用關鍵字抡柿。 以上是java中的常用關鍵字,最低要求眼熟氏堤。 標識符 1. 標識符可以由字母沙绝、數(shù)字、下劃線(_)鼠锈、美...
    Sunshine_YL閱讀 260評論 0 0
  • 這是一篇總結帖购笆,歡迎朋友們補充~ 1.病從口入粗悯,禍從口出。 2.路遙知馬力同欠,日久見人心样傍。 3.地低成海横缔,人低成王。...
    仙人掌cactus閱讀 1,111評論 1 5
  • 感恩大自然的恩典衫哥,春光無限茎刚,氣候適宜,充滿了生命的暖意 感恩合伙人夫妻兩的信任撤逢,讓一切成為最好的安排 感恩老公關鍵...
    祺予閱讀 135評論 1 3
  • Dispatch Queues的生成可以有這幾種方式: 1.dispatch_queue_tqueue=dispa...
    Ryan_RH閱讀 370評論 0 0