正交設(shè)計(jì),OO與SOLID

正交設(shè)計(jì)讥脐,是普遍的設(shè)計(jì)原則遭居,與粒度無(wú)關(guān),與編程范式無(wú)關(guān)旬渠,更與具體的實(shí)現(xiàn)語(yǔ)言無(wú)關(guān)俱萍。(雖然確實(shí)在不同的編程范式下,或使用不同的編程語(yǔ)言時(shí)坟漱,具體的解決方法或難易程度不同鼠次,這也正是為何我們總是在尋找更適合的編程范式,更高效的編程語(yǔ)言的原因)芋齿。

而具體到面向?qū)ο?/strong>范式腥寇,我們都知道著名的SOLID原則。但是:這五個(gè)原則是怎么來(lái)的觅捆?它們的目的何在赦役?它們的關(guān)系如何?

為了搞清楚這些疑問(wèn)栅炒,我們?cè)俅位氐阶畛醯膯?wèn)題:

  1. 軟件模塊該如何劃分掂摔?(怎么分)
  2. 模塊間API該如何定義?(怎么合)

怎樣進(jìn)行分解赢赊?

模塊的劃分乙漓,是一個(gè)問(wèn)題分解的過(guò)程。

在文章《VBD (Volatility Based Decomposition)》里释移,引用了一篇70年代的論文《On the Criteria to be Used in Decomposing Systems into Modules》叭披。

在這篇論文里,作者通過(guò)一個(gè)小例子玩讳,清晰的指出了軟件模塊劃分應(yīng)該以基于信息隱藏為目的涩蜘,以職責(zé)劃分為手段嚼贡,從而封裝變化,讓軟件更加容易修改(即Kent Beck的理想:局部化影響)同诫。

這篇文章也展示了:基于流程(過(guò)程)的分解粤策,是一種極其脆弱的模塊劃分方式。因而我們應(yīng)該離基于過(guò)程的分解越遠(yuǎn)越好误窖。

這也是為何Matt Cochran將這種分解方法稱做:基于易變性的分解Volatility Based Decomposition)叮盘。

總而言之胎署,變化應(yīng)對(duì)變化霉咨,是軟件設(shè)計(jì)最大的挑戰(zhàn),目的和意義验懊。

面向?qū)ο缶烤挂鉀Q什么問(wèn)題吭服?

最近幾年嚷堡,我聽(tīng)到太多針對(duì)OO的批評(píng),其中最為奇葩的說(shuō)法是:OO只適合GUI編程艇棕。因?yàn)?code>GUI組件概念上更接近于對(duì)象蝌戒,至于其它領(lǐng)域則不太合適。

對(duì)提出這樣高論的人沼琉,我相當(dāng)確信北苟,他們不僅對(duì)于面向?qū)ο?/strong>一無(wú)所知,更是對(duì)于復(fù)雜軟件所面臨的真正挑戰(zhàn)打瘪,以及軟件設(shè)計(jì)究竟要解決什么問(wèn)題一無(wú)所知友鼻。

前兩天偶然從東海陳光劍的文章《函數(shù)式編程與面向?qū)ο缶幊蘙5]:編程的本質(zhì)》讀到軟件模塊化的目的和價(jià)值(雖然他用的是結(jié)構(gòu)化,但在我看來(lái)也是在談模塊化)闺骚,非常精彩彩扔,深合我意:

(軟件設(shè)計(jì)是一個(gè))層次化分解與重新復(fù)合的過(guò)程

這個(gè)思維過(guò)程, 并非是受計(jì)算機(jī)的限制而產(chǎn)生,它反映的是人類(lèi)思維的局限性僻爽。我們的大腦一次只能處理很少的概念虫碉。生物學(xué)中被廣為引用的 一篇論文指出我們我們的大腦中只能保存7 ± 2個(gè)信息塊。我們對(duì)人類(lèi)短期記憶的認(rèn)識(shí)可能會(huì)有變化胸梆,但是可以肯定的是它是有限的敦捧。底線就是我們不能處理一大堆亂糟糟的對(duì)象或像蘭州拉面似的代碼。

我們需要結(jié)構(gòu)化并非是因?yàn)榻Y(jié)構(gòu)化的程序看上去有多么美好碰镜,而是我們的大腦無(wú)法有效的處理非結(jié)構(gòu)化的東西兢卵。我們經(jīng)常說(shuō)一些代碼片段是優(yōu)雅的或美觀的,實(shí)際上那只意味 著它們更容易被人類(lèi)有限的思維所處理绪颖。優(yōu)雅的代碼創(chuàng)造出尺度合理的代碼塊秽荤,它正好與我們的『心智消化系統(tǒng)』能夠吸收的數(shù)量相符。

那么,對(duì)于程序的復(fù)合而言王滤,正確的代碼塊是怎樣的?它們的表面積必須要比它們的體積增長(zhǎng)的更為緩慢滓鸠。我喜歡這個(gè)比喻雁乡,因?yàn)閹缀螌?duì)象的表面積是以尺寸的平方的速度增長(zhǎng)的,而體積是以尺寸的立方的速度增長(zhǎng)的糜俗,因此表面積的增長(zhǎng)速度小于體積踱稍。

代碼塊的表面積是是我們復(fù)合代碼塊時(shí)所需要的信息。代碼塊的體積 是我們?yōu)榱藢?shí)現(xiàn)它們所需要的信息悠抹。一旦代碼塊的實(shí)現(xiàn)過(guò)程結(jié)束珠月,我們就可以忘掉它的實(shí)現(xiàn)細(xì)節(jié),只關(guān)心它與其他代碼塊的相互影響楔敌。在面向?qū)ο缶幊讨衅】妫?lèi)或接口的聲明就是表面。在函數(shù)式編程中卵凑,函數(shù)的聲明就是表面庆聘。我把事情簡(jiǎn)化了一些,但是要點(diǎn)就是這些勺卢。

怎樣才能做到表面積增長(zhǎng)速度小于體積增長(zhǎng)速度伙判?當(dāng)然是分解信息隱藏黑忱,抽象宴抚。而這些也正是面向?qū)ο?/strong>所追求和擅長(zhǎng)的。

面向?qū)ο?/strong>主要目的是提供一種語(yǔ)言級(jí)的模塊化支持甫煞。雖然在一些數(shù)學(xué)家看來(lái):由于面向?qū)ο?/strong>沒(méi)有很好的數(shù)學(xué)理論基礎(chǔ)菇曲,因而必然是一個(gè)錯(cuò)誤的方法論「Х停可對(duì)于如何編寫(xiě)一個(gè)易于應(yīng)對(duì)變化的軟件羊娃,并不是一個(gè)純數(shù)學(xué)理論問(wèn)題(或許確實(shí)有數(shù)學(xué)家也可以抽象出一套數(shù)學(xué)理論),而更多的是一個(gè)實(shí)踐問(wèn)題埃跷。作為長(zhǎng)期處于實(shí)踐一線的我們蕊玷,不應(yīng)把幾個(gè)數(shù)學(xué)家的看法當(dāng)作金科玉律(對(duì)于那些沒(méi)有實(shí)踐經(jīng)驗(yàn),卻對(duì)如何實(shí)踐指手畫(huà)腳的純理論派弥雹,每次看到他們的不負(fù)責(zé)任的言論垃帅,考慮到他們的影響力和對(duì)新手的誤導(dǎo),就禁不住想對(duì)他們豎中指)(參見(jiàn)《學(xué)習(xí)的邏輯3: 三人行必有我徒》)剪勿。

軟件工業(yè)最近20年來(lái)贸诚,能夠構(gòu)建如此大規(guī)模的需求頻繁變化的軟件系統(tǒng),很大程度上得益于面向?qū)ο?/strong>對(duì)于模塊化的良好支持。

而現(xiàn)在風(fēng)頭正勁的微服務(wù)化酱固,無(wú)非是把模塊化的思想械念,從進(jìn)程內(nèi)模塊(類(lèi)),變?yōu)檫M(jìn)程間而已运悲。

OO和FP

面向?qū)ο?/strong>與函數(shù)式編程的最大區(qū)別在于數(shù)據(jù)是否是強(qiáng)制不變性龄减。這個(gè)前提,導(dǎo)致了一系列其它的差異班眯。

因?yàn)榭勺冃裕?strong>面向?qū)ο?/strong>可以將算法和數(shù)據(jù)放在一起希停,當(dāng)數(shù)據(jù)是一種實(shí)現(xiàn)細(xì)節(jié)時(shí),可對(duì)其進(jìn)行信息隱藏封裝署隘。但在Pure FP里宠能,數(shù)據(jù)和算法是必須分離的。這種分離磁餐,在很多場(chǎng)景下违崇,對(duì)于信息隱藏相當(dāng)不利(在這里我們先不談性能)。因而诊霹,當(dāng)系統(tǒng)規(guī)模足夠復(fù)雜時(shí)亦歉,FP對(duì)于構(gòu)造易于維護(hù)軟件的能力比面向?qū)ο?/strong>要弱。

因而畅哑,FP為了實(shí)用肴楷,要么部分放棄對(duì)不變性的堅(jiān)持(如LISP所做的那樣),從而允許模擬面向?qū)ο蠓妒剑▍⒁?jiàn)SICP)荠呐;要么通過(guò)Existential Quantification赛蔫,來(lái)模擬OO運(yùn)行時(shí)多態(tài),以達(dá)到信息隱藏泥张,隔離變化的目的呵恢;要么使用輕量級(jí)進(jìn)程輕量很關(guān)鍵):讓每個(gè)輕量級(jí)進(jìn)程承擔(dān)一個(gè)很小的職責(zé),從進(jìn)程外部看媚创,每個(gè)輕量級(jí)進(jìn)程都可以有可修改的數(shù)據(jù)渗钉,以及基于消息的行為驅(qū)動(dòng)(如erlangakkaActor模型),而這正是對(duì)于smalltalk的對(duì)象模擬钞钙,從而緩解了不變性帶來(lái)的尷尬鳄橘。進(jìn)而也說(shuō)明了基于高內(nèi)聚,低耦合原則進(jìn)行的模塊化是超越范式的芒炼。

因而瘫怜,一些FPer對(duì)于OO的盲目批評(píng),和認(rèn)為面向?qū)ο?/strong>只適合GUI領(lǐng)域一樣本刽,都并不真正明白一個(gè)復(fù)雜軟件的關(guān)鍵挑戰(zhàn)鲸湃,以及解決方案何在赠涮。

當(dāng)然,具體到編程語(yǔ)言暗挑,即便都是OO語(yǔ)言笋除,差別也巨大。但這是另外一個(gè)宏大的話題炸裆,這里暫且不談垃它。只重點(diǎn)說(shuō)一句:不要把某種OO語(yǔ)言,當(dāng)作OO本身晒衩。

關(guān)于FPOO的話題,值得專門(mén)寫(xiě)一篇文章全面論述墙歪,而本文的目的在于介紹SOLID听系,因而不再贅述。

正交原則與SOLID的關(guān)系

一個(gè)好的面向?qū)ο笤O(shè)計(jì)虹菲,自然是符合高內(nèi)聚靠胜,低耦合原則的對(duì)象劃分和協(xié)作方式。

單一職責(zé)開(kāi)放封閉毕源,更多的在強(qiáng)調(diào)類(lèi)劃分時(shí)的高內(nèi)聚浪漠;而里氏替換依賴倒置霎褐,接口隔離則更多的強(qiáng)調(diào)類(lèi)與類(lèi)之間協(xié)作接口(即API)定義的低耦合址愿。

高內(nèi)聚(怎么分)

單一職責(zé),通過(guò)對(duì)變化原因的識(shí)別冻璃,將一個(gè)承擔(dān)多重職責(zé)的類(lèi)响谓,不斷分割為更小的,只具備單一變化原因的類(lèi)省艳。而單一變化原因指的是:一個(gè)變化娘纷,會(huì)引起整個(gè)類(lèi)都發(fā)生變化。只有關(guān)聯(lián)極其緊密的情況跋炕,才會(huì)導(dǎo)致這樣的局面赖晶。因而,單一職責(zé)高內(nèi)聚某種程度是同義詞辐烂。

單一職責(zé)原則本身遏插,并沒(méi)有明確指示我們?cè)撊绾闻卸ㄒ粋€(gè)類(lèi)屬于單一職責(zé)的,以及如何達(dá)到單一職責(zé)的狀態(tài)纠修。而策略消除重復(fù)涩堤,分離不同變化方向,正是讓類(lèi)達(dá)到單一職責(zé)的策略與途徑分瘾。

消除重復(fù)以達(dá)到單一職責(zé)
消除重復(fù)以達(dá)到單一職責(zé)
分離變化方向以達(dá)到單一職責(zé)
分離變化方向以達(dá)到單一職責(zé)

低耦合 (怎么合)

開(kāi)放封閉原則胎围,正是通過(guò)將不同變化方向進(jìn)行分離吁系,從而達(dá)到對(duì)于已經(jīng)出現(xiàn)的變化方向,對(duì)于修改是封閉的白魂,對(duì)于擴(kuò)展是開(kāi)放的汽纤。

開(kāi)放封閉原則
開(kāi)放封閉原則

里氏替換原則強(qiáng)調(diào)的是,一個(gè)子類(lèi)不應(yīng)該破壞其父類(lèi)客戶之間的契約福荸。唯有如此蕴坪,才能保證:客戶與其父類(lèi)所暴露的接口(即API)所產(chǎn)生的依賴關(guān)系是穩(wěn)定的。子類(lèi)只應(yīng)該成為隱藏在API背后的某種具體實(shí)現(xiàn)方式敬锐。

里氏替換原則
里氏替換原則

依賴倒置原則則強(qiáng)調(diào):為了讓依賴關(guān)系是穩(wěn)定的背传,不應(yīng)該由實(shí)現(xiàn)側(cè)根據(jù)自己的技術(shù)實(shí)現(xiàn)方式定義接口,然后強(qiáng)迫上層(即客戶)依賴這種不穩(wěn)定的API定義台夺,而是應(yīng)該站在上層(即客戶)的角度去定義API(正所謂依賴倒置)径玖。

但是,雖然接口由上層定義颤介,但最終接口的實(shí)現(xiàn)卻依然由下層完成梳星,因此依賴倒置描述為:上層不依賴下層,下層也不依賴上層滚朵,雙方共同依賴于抽象冤灾。

依賴倒置原則
依賴倒置原則

最后,接口隔離原則強(qiáng)調(diào)的是:不應(yīng)該強(qiáng)迫客戶依賴它不需要的東西辕近。顯然韵吨,這是縮小依賴范圍策略在面向?qū)ο蠓妒较碌漠a(chǎn)物。

接口隔離原則
接口隔離原則

結(jié)論

正交設(shè)計(jì)是一種與范式移宅,語(yǔ)言無(wú)關(guān)的設(shè)計(jì)原則学赛。為了解決在模塊化的過(guò)程中,如何讓軟件在長(zhǎng)期范圍內(nèi)更容易應(yīng)對(duì)變化吞杭。

面向?qū)ο?/strong>是一種對(duì)模塊化支持良好的范式盏浇。通過(guò)高內(nèi)聚,低耦合原則芽狗,或正交策略的運(yùn)用绢掰,面向?qū)ο?/strong>范式下SOLID原則會(huì)自然浮現(xiàn)。

我們耳熟能詳?shù)能浖O(shè)計(jì)相關(guān)原則童擎,模式與實(shí)踐的關(guān)系如下:


軟件設(shè)計(jì)
軟件設(shè)計(jì)

關(guān)于正交設(shè)計(jì)的更多細(xì)節(jié)滴劲,請(qǐng)參閱《變化驅(qū)動(dòng):正交設(shè)計(jì)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顾复,一起剝皮案震驚了整個(gè)濱河市班挖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芯砸,老刑警劉巖萧芙,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件给梅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡双揪,警方通過(guò)查閱死者的電腦和手機(jī)动羽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)渔期,“玉大人运吓,你說(shuō)我怎么就攤上這事》杼耍” “怎么了拘哨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)信峻。 經(jīng)常有香客問(wèn)我倦青,道長(zhǎng),這世上最難降的妖魔是什么站欺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任姨夹,我火速辦了婚禮纤垂,結(jié)果婚禮上矾策,老公的妹妹穿的比我還像新娘。我一直安慰自己峭沦,他們只是感情好贾虽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著吼鱼,像睡著了一般蓬豁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上菇肃,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天地粪,我揣著相機(jī)與錄音,去河邊找鬼琐谤。 笑死蟆技,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斗忌。 我是一名探鬼主播质礼,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼织阳!你這毒婦竟也來(lái)了眶蕉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤唧躲,失蹤者是張志新(化名)和其女友劉穎造挽,沒(méi)想到半個(gè)月后碱璃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刽宪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年厘贼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片圣拄。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嘴秸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出庇谆,到底是詐尸還是另有隱情岳掐,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布饭耳,位于F島的核電站串述,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏寞肖。R本人自食惡果不足惜纲酗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望新蟆。 院中可真熱鬧觅赊,春花似錦、人聲如沸琼稻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)帕翻。三九已至鸠补,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘀掸,已是汗流浹背紫岩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留睬塌,地道東北人泉蝌。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像衫仑,于是被迫代替她去往敵國(guó)和親梨与。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容