欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
變化驅動(dòng):正交設計

一個(gè)出發(fā)點(diǎn)


當談起軟件設計目的時(shí),能夠獲得所有人認同的答案只有一個(gè):功能實(shí)現。 因為這是一個(gè)軟件存在的根本原因。


而在計算機軟件發(fā)展的初期,這一點(diǎn)也正是所有人做軟件設計的唯一動(dòng)機。因而,很自然的,整個(gè)軟件都被放在單一過(guò)程中,然后用到處存在的goto語(yǔ)句控制流程。


盡管理論上講,任意復雜的系統都可以被放入同一個(gè)函數里。但隨著(zhù)軟件越來(lái)復雜,即便是智商最為發(fā)達的程序員也發(fā)現,單一過(guò)程的復雜度已經(jīng)超出他的掌控極限。這逼迫人們必須對大問(wèn)題進(jìn)行分解,分而治之。


時(shí)至今日,盡管超大函數,上帝類(lèi)依然并不罕見(jiàn),但當大到一定程度,上帝類(lèi)的創(chuàng )造者最終也會(huì )發(fā)現自己終究沒(méi)有上帝般的掌控力。因而,哪怕是軟件設計素養為負值的開(kāi)發(fā)者,或多或少也會(huì )對一個(gè)復雜系統進(jìn)行一定程度的拆分。


這就是模塊化設計的最初動(dòng)機。


兩個(gè)問(wèn)題


一旦人們開(kāi)始進(jìn)行進(jìn)行模塊化拆分,就必須解決如下兩個(gè)問(wèn)題:

  • 究竟軟件模塊該怎樣劃分才是合理的?

  • 將一個(gè)大單元劃分為多個(gè)小單元之后,它們之間必然要通過(guò)銜接點(diǎn)進(jìn)行合作。如果我們把這些銜接點(diǎn)看作API,那么問(wèn)題就變?yōu)椋涸鯓佣xAPI才是合理的?


更簡(jiǎn)單的說(shuō):怎么分?然后再怎么合?


△ 分工與合作


而這兩個(gè)問(wèn)題的答案,正是現代軟件設計的核心關(guān)注點(diǎn)。


三方關(guān)系


為了找到這兩個(gè)問(wèn)題的答案,我們需要重新回到最初的問(wèn)題:為何要做軟件設計?


Kent Beck給出的答案是:軟件設計是為了在讓軟件在長(cháng)期范圍內容易應對變化。


在這個(gè)精煉的定義中,包含著(zhù)三個(gè)關(guān)鍵詞:長(cháng)期,容易,變化。這意味著(zhù):

  • 越是需要長(cháng)期維護的項目,變化更多,也更難預測變化的方式;

  • 軟件設計,事關(guān)成本;

  • 如何在難以預測的千變萬(wàn)化中,保持低廉的變更成本,正是軟件設計要解決的問(wèn)題。


對此,Kent Beck提出了一個(gè)更為精煉的原則:局部化影響。意思是說(shuō):我們希望,任何一個(gè)變化,對于我們當前的軟件設計影響范圍都可以控制在一個(gè)盡量小的局部。


這當然是所有嚴肅的軟件從業(yè)者都夢(mèng)寐以求的。


可問(wèn)題在于,如何才能做到?


內聚與耦合


每個(gè)讀過(guò)基礎軟件工程教程的人都知道:一個(gè)易于應對變化的軟件設計應該遵從高內聚,低耦合原則。


所謂內聚性,關(guān)注的是一個(gè)軟件單位內部的關(guān)聯(lián)緊密程度。因而高內聚追求的是關(guān)聯(lián)緊密的事物應該被放在一起,并且只有關(guān)聯(lián)緊密的事物才應該被放在一起。簡(jiǎn)單說(shuō),就是Unix的設計哲學(xué):

Do One Thing, Do It Well。


耦合性,則是強調兩個(gè)或多個(gè)軟件單位之間的關(guān)聯(lián)緊密程度。因而低耦合追求的是,軟件單位之間盡可能不要相互影響。


這樣的解釋?zhuān)瑢τ诤芏嗳硕?,依然?huì )感到過(guò)于抽象。但如果我們進(jìn)一步思考,就會(huì )意識到:看似神秘的內聚耦合,正好對應最初的兩個(gè)問(wèn)題:

  • 當我們劃分模塊時(shí),要讓每個(gè)模塊都盡可能高內聚;

  • 而當我們定義模塊之間的API時(shí),需要讓雙方盡可能低耦合。


如果用圖來(lái)展現,就是下面的過(guò)程與關(guān)系:


△ 高內聚,低耦合


這幅圖揭示了模塊化設計的全部:首先將一個(gè)低內聚的模塊首先拆分為多個(gè)高內聚的模塊;然后再考慮這多個(gè)模塊之間的API設計,以降低這些高內聚的軟件單元之間的耦合度。


除了內聚與耦合之外,上面這幅圖還揭示了另外一種關(guān)系:正交。具備正交關(guān)系的兩個(gè)模塊,可以做到一方的變化不會(huì )影響另外一方的變化。換句話(huà)說(shuō),雙方各自獨自變化,互不影響。


而這幅圖的右側,正是我們模塊化的目標。它描述了永恒的三方關(guān)系:客戶(hù),API,實(shí)現,以及它們之間的關(guān)系。這個(gè)三方關(guān)系圖清晰的指出了我們應該關(guān)注的內聚性,耦合性,以及正交性都發(fā)生在何處。


四個(gè)策略


相對于局部化影響,高內聚,低耦合原則已經(jīng)清晰和具體許多。但依然更像是在描述目標或結果,而沒(méi)有指明該如何達成的方法。雖然《代碼大全》列舉?了那么多的內聚性耦合性的分類(lèi),但對于想應用它們的軟件設計人員,依然感覺(jué)如隔靴撓癢,不得要領(lǐng)。


因而,我們需要從它推導出更為明確,更具指導性和操作性的設計原則。


為了做到這一點(diǎn),我們必須首先搞清楚:內聚耦合,和變化之間的關(guān)系是怎樣的,以至于高內聚、低耦合的模塊化方式能夠更容易應對變化?


我們再次回顧內聚耦合的定義:它們是用來(lái)衡量代碼元素之間的關(guān)聯(lián)緊密程度。很容易得知:元素之間的關(guān)聯(lián)緊密程度越高,一個(gè)變化引起它們相互之間都發(fā)生變化的可能性就越高。反之,關(guān)聯(lián)程度越弱,變化引起的連鎖變化的概率就越低。


因而,我們要把容易互相影響的、關(guān)聯(lián)程度緊密的元素,都封裝在一個(gè)模塊內部(而這正是我們老生常談的封裝變化的動(dòng)機);同時(shí)讓模塊之間的關(guān)聯(lián)緊密程度盡可能降低,以讓模塊間盡可能不要相互影響。從而最終做到局部化影響。


因而,Uncle Bob說(shuō):一個(gè)類(lèi)只應該有一個(gè)變化原因。他進(jìn)一步談到:所謂一個(gè)變化原因,指一個(gè)變化會(huì )導致整個(gè)類(lèi)所包含的各個(gè)元素都要發(fā)生變化。為何會(huì )如此?因為它們的關(guān)聯(lián)程度太緊密(因而高內聚),以至于牽一發(fā)而動(dòng)全身。


因此,Uncle Bob將職責定義為變化原因。


在一些時(shí)候,我們可以直接判定一個(gè)模塊是否包含多重職責。因為它們確實(shí)包含著(zhù)明顯沒(méi)有什么關(guān)聯(lián)的兩組代碼元素。


但在另外一些場(chǎng)景下,我們則無(wú)法清晰的判定:一個(gè)模塊是否真的包含多重變化原因,或多重職責。比如如下代碼:

struct Student
{
 char name[MAX_NAME_LEN];
 unsigned int height;
};

void sort_students_by_height(Student students[], size_t num_of_students)
{
 for(size_t y=0; y <>1; y++)
 {
   for(size_t x=1; x < num_of_students="" -="" y;="" x++)="">
   {
     if(students[x].height > students[x-1].height)
     {
       SWAP(students[x], students[x-1]);
     }
   }
 }
}

這是一個(gè)對學(xué)生按照身高從低到高進(jìn)行排序的算法。對于這段代碼,如果我們進(jìn)行猜測,會(huì )發(fā)現很多點(diǎn)都有變化的可能,如果對這些變化都進(jìn)行分離和管理,確實(shí)會(huì )提高系統的內??聚度。但如果我們現在就將整個(gè)系統每個(gè)可能的變化點(diǎn)都分離出來(lái),無(wú)疑會(huì )讓整個(gè)系統陷入無(wú)邊無(wú)際的不必要的復雜度。


破解這類(lèi)難題的方法是:既然我們知道高內聚,低耦合的設計是為了軟件更容易應對變化的,那么我們?yōu)楹尾环催^(guò)來(lái),讓實(shí)際發(fā)生的需求變化來(lái)驅動(dòng)我們識別變化,管理變化,從而讓我們的系統達到恰如其分的內聚度和耦合度?


策略一:消除重復


首先進(jìn)入我們射程的就是重復代碼。編寫(xiě)重復代碼不僅僅會(huì )讓有追求的程序員感到乏味。真正致命的是:“重復”極度違背高內聚、低耦合原則,從而會(huì )大幅提升軟件的長(cháng)期維護成本。


我們之前已經(jīng)討論過(guò),所謂高內聚,指的是關(guān)聯(lián)緊密的事物應該被放在一起。沒(méi)有比兩段完全相同的代碼關(guān)聯(lián)更為緊密。因而重復代碼意味著(zhù)低內聚。


而更為糟糕的是,本質(zhì)重復的代碼,其實(shí)都在表達(即依賴(lài))同一項知識。如果它們表達(即依賴(lài))的知識發(fā)生了變化,這些重復的代碼統統都要修改。因而, 重復代碼也意味著(zhù)高耦合。


△ 重復代碼意味著(zhù)耦合


因而,對于完全重復的代碼進(jìn)行消除,合二為一,會(huì )讓系統更加高內聚、低耦合。


而更為關(guān)鍵的是:如果兩個(gè)模塊之間是部分重復的,則發(fā)出了一個(gè)重要的信號:這兩個(gè)模塊都至少存在兩個(gè)變化原因,或兩重職責。


如下圖所示,兩個(gè)模塊存在著(zhù)部分重復。站在系統的角度看,它們之間存在著(zhù)不變的部分(即重復的部分);也存在變化的部分(即差異的部分)。這意味著(zhù)這兩個(gè)模塊都存在兩個(gè)變化原因。


變化與不變:多重職責


對于這一類(lèi)型的重復,比較典型的情況有兩種:調用型重復,以及回調型重復。它們的命名來(lái)源于:在重復消除后,重復與差異之間的關(guān)系是調用,還是回調。



調用型重復


回調型重復


由此,我們得到了第一個(gè)策略:消除重復。


這個(gè)策略,非常明確,極具可操作性:當你看到重復時(shí),盡力消除它。


這個(gè)策略,明顯提高系統的內聚性,降低了耦合性。除此之外,還得到一個(gè)重大收益:可重用性。事實(shí)上,消除重復的過(guò)程,正是一個(gè)提高系統可重用性的過(guò)程。


另外對于回調型重復的消除,也是一個(gè)提高系統可擴展性的過(guò)程。


策略二:分離不同的變化方向


除了重復代碼外,另外一個(gè)驅動(dòng)系統朝向高內聚方向演進(jìn)的信號是:我們經(jīng)常需要因為同一類(lèi)原因,修改某個(gè)模塊。而這個(gè)模塊的其它部分卻保持不變。


比如,在之前我們對學(xué)生按照身高從低到高排序的例子中,如果現在我們需要增加對老師按照身高從低到高排序的需求,我們就知道,排序對象是一個(gè)新的變化方向。于是,我們將代碼重構為:

template
void bulb_sort(T objects[], size_t num_of_objects)
{
 for(size_t y=0; y < num_of_objects="" -="">1; y++)
 {
   for(size_t x=1; x < num_of_objects="" -="" y;="" x++)="">
   {
     if(objects[x].height > objects[x-1].height)
     {
        SWAP(objects[x], objects[x-1]);
     }
   }
 }
}

如果隨后又出現一個(gè)新的需求:按照學(xué)生身高從高到低排序(原來(lái)為從低到高)。此時(shí)我們知道排序規則也是一個(gè)變化的方向。因此,我們將這個(gè)變化方向也從現有代碼中分離出去。然后得到:

template
void bulb_sort(T objects[], size_t num_of_objects)
{
 for(size_t y=0; y < num_of_objects="" -="">1; y++)
 {
   for(size_t x=1; x < num_of_objects="" -="" y;="" x++)="">
   {
     if(objects[x] > objects[x-1])
     {
       SWAP(objects[x], objects[x-1]);
     }
   }
 }
}


分離不同變化方向,目標在于提高內聚度。因為多個(gè)變化方向,意味著(zhù)一個(gè)模塊存在多重職責。將不同的變化方向進(jìn)行分離,也意味著(zhù)各個(gè)變化方向職責的單一化。


從這個(gè)例子可以看出,此策略的應用時(shí)機也非常明確:當你發(fā)現需求導致一個(gè)變化方向出現時(shí),將其從原有的設計中分離出去。


△ ?分離新的變化方向


對于變化方向的分離,也得到了另外一個(gè)我們追求的目標:可擴展性。


如果我們足夠細心,會(huì )發(fā)現策略消除重復分離不同變化方向是兩個(gè)高度相似和關(guān)聯(lián)的策略:


它們都是關(guān)注于如何對原有模塊進(jìn)行拆分,以提高系統的內聚性。(雖然同時(shí)也往往伴隨著(zhù)耦合度的降低,但這些耦合度的降低都發(fā)生在別處,并未觸及該如何定義API以降低客戶(hù)與API之間耦合度)。


另外,如果兩個(gè)模塊有部分代碼是重復的,往往意味著(zhù)不同變化方向。


盡管如此,我們依然需要兩個(gè)不同的策略。這是因為:變化方向,并不總是以重復代碼的形式出現的(其典型癥狀是霰彈式修改,或者if-else、switch-case、模式匹配);盡管其背后往往存在一個(gè)以重復代碼形式表現的等價(jià)形式(這也是為何copy-paste-modify如此流行的原因)。


策略三:縮小依賴(lài)范圍


前面兩個(gè)策略解決了軟件單元該如何劃分的問(wèn)題?,F在我們需要關(guān)注模塊之間的粘合點(diǎn)——即API——的定義問(wèn)題。


需要強調的是:兩個(gè)模塊之間并不存在耦合,它們的都共同耦合在A(yíng)PI上。因而 API如何定義才能降低耦合度,才是我們應該關(guān)注的重點(diǎn)。



耦合點(diǎn):API


從這幅圖可以看出,對于A(yíng)PI定義所帶來(lái)的耦合度影響,需要遵循如下原則:

  • 首先,客戶(hù)實(shí)現模塊的數量,會(huì )對耦合度產(chǎn)生重大的影響。它們數量越多,意味著(zhù) API 變更的成本越高,越需要花更大的精力來(lái)仔細斟酌。

  • 其次,對于影響面大的API(也意味著(zhù)耦合度高),需要使用更加彈性的API定義框架,以有利于向前兼容性。


而具體到策略縮小依賴(lài)范圍,它強調:

  • API 應包含盡可能少的知識。因為任何一項知識的變化都會(huì )導致雙方的變化;

  • API 也應該高內聚,而不應該強迫API的客戶(hù)依賴(lài)它不需要的東西。


策略四:向著(zhù)穩定的方向依賴(lài)


但是,無(wú)論我們如何縮小依賴(lài)范圍,如果兩個(gè)模塊需要協(xié)作,它們之間必然存在耦合點(diǎn)(即API)。降低耦合度的努力似乎已經(jīng)走到了盡頭。


我們知道,耦合的最大問(wèn)題在于:耦合點(diǎn)的變化,會(huì )導致依賴(lài)方跟著(zhù)變化。但這也意味著(zhù),如果耦合點(diǎn)從來(lái)不會(huì )變化,那么依賴(lài)方也就不會(huì )因此而變化。換句話(huà)說(shuō),耦合點(diǎn)越穩定,依賴(lài)方受耦合變化影響的概率就越低。


由此,我們得到最后一個(gè)策略:向著(zhù)穩定的方向依賴(lài)。


那么,究竟什么樣的API更傾向于穩定?不難知道,站在What,而不是How的角度;即

站在需求的角度,而不是實(shí)現方式的角度定義API,會(huì )讓其更加穩定。


而需求的提出方,一定是客戶(hù)端,而不是實(shí)現側。這就意味著(zhù),我們在定義接口時(shí),應該站在客戶(hù)的角度,思考用戶(hù)的本質(zhì)需要,由此來(lái)定義API。而不是站在技術(shù)實(shí)現的方便程度角度來(lái)思考API定義。


而這正是封裝信息隱藏的關(guān)鍵。


小結


這四個(gè)策略,前兩者聚焦于如何劃分模塊,后兩個(gè)聚焦于如何定義模塊間的API。換句話(huà)說(shuō),前兩者關(guān)注于“如何分”,后兩條聚焦于“怎么合”。


這四個(gè)策略的背后動(dòng)力非常明確:變化。前兩者,都是在明確的變化方向被第一次識別之后(所謂第一顆子彈),進(jìn)行策略運用,以讓模塊在變化面前越來(lái)越高內聚。而后兩者,則是在模塊職責分離之后,需要定義模塊間API時(shí),盡可能考慮不同的API定義方式對于依賴(lài)雙方的影響,以達到低耦合。


由于這四個(gè)策略致力于讓系統朝著(zhù)更具正交性的方向演進(jìn),因而它們也被稱(chēng)做正交策略,或者正交四原則。


總結


本文首先從一個(gè)出發(fā)點(diǎn)出發(fā):為了降低軟件復雜度,提升可重用性,我們需要模塊化。


由此得到了兩個(gè)問(wèn)題:模塊劃分必然要解決如何劃分,以及模塊間如何協(xié)作(API 定義)的問(wèn)題。


基于軟件易于應對變化的角度出發(fā)。高內聚、低耦合原則是最為核心和關(guān)鍵的高層原則?;诖宋覀兊玫搅嗽谀K化過(guò)程中,我們真正需要關(guān)注的三方關(guān)系。


為了讓高內聚、低耦合更具指導性和操作性,我們提出了四個(gè)策略。它們以變化驅動(dòng),讓系統逐步向更好的正交性演進(jìn)的策略,因此也被稱(chēng)做正交策略正交原則。


我們已經(jīng)在多個(gè)系統的設計和開(kāi)發(fā)中,以這四個(gè)原則來(lái)驅動(dòng)我們的軟件設計,不僅讓我們的系統在保持簡(jiǎn)單的同時(shí),具備所有必要的靈活性。也讓設計和開(kāi)發(fā)活動(dòng)變得高度有章可循,讓團隊生產(chǎn)率得以大幅提升。


最后,推薦劉光聰的文章《實(shí)戰正交設計》。這篇文章通過(guò)一個(gè)例子,來(lái)展示了正交策略是如何驅動(dòng)出更加正交的設計的。


而正交設計與SOLID的關(guān)系,可參閱《正交設計,OO與SOLID》。


附錄


而我的朋友及前同事李光磊對此精煉的總結道:

變化導致的修改有兩類(lèi):

  • 一個(gè)變化導致多處修改(重復);

  • 多個(gè)變化導致一處修改(多個(gè)變化方向);


由此得到前兩個(gè)策略:消除重復;分離不同變化方向。

除此之外,我們要努力消除變化發(fā)生時(shí)不必要的修改,也有兩種方式:

  • 不依賴(lài)不必要的依賴(lài);

  • 不依賴(lài)不穩定的依賴(lài);


這就是后面兩個(gè)策略:縮小依賴(lài)范圍,向著(zhù)穩定的方向依賴(lài)。


從光磊這個(gè)精彩總結中可以清晰的看出:

  • 一切圍繞著(zhù)變化:由變化驅動(dòng),反過(guò)來(lái)讓系統演進(jìn)的更容易應對變化;

  • 這四個(gè)策略都是在讓系統更加局部化影響。

  • 這四個(gè)策略的完備性。




這次征得老袁的同意,發(fā)表他的這篇大作。本文基本上將模塊化設計需要應對的重復問(wèn)題、變化問(wèn)題窮盡了,關(guān)鍵在于文章還給出了具有較強實(shí)操性的四條原則,提出“正交設計”的思想,值得深思與學(xué)習。


老袁是我之前在ThoughtWorks的同事。在我眼中,從來(lái)都是如神龍見(jiàn)首不見(jiàn)尾,常年奮戰在客戶(hù)第一線(xiàn)。公司內部常有袁大師的傳奇故事在地下傳播,屬于那種在客戶(hù)那里虎軀一震就有小弟拜倒的牛逼人物。最初聽(tīng)說(shuō),我還認為不要太浮夸了。后來(lái)在咨詢(xún)客戶(hù)那里認識了幾個(gè)袁大師帶過(guò)的“徒弟”,提及袁大師,那真是敬仰之情如滔滔江水奔流不息啊,而我的地位也瞬間從“教練”上升為“師叔”了??磥?lái)傳奇人物就是不凡,原來(lái)自帶加分光環(huán)的。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
用軟件量度評估軟件重構
Eric Raymond談模塊化原則,膠合層和面向對象的缺陷
讀書(shū)日志:代碼大全之第六章
耦合是什么意思
我理解中的應用架構
降低耦合(1)API函數設計方法討論
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久