<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    自寫自看

    軟件最大的追求是什么? (轉載)

    前段時間讀了《軟件的最大追求是什么》,擊節叫好,深以為然,雖然該文章很多地方顯得有點極端。

    如今的軟件系統越來越復雜,如果軟件的結構不好會影響軟件的可維護性,重構代碼是一件極其痛苦的事情。

    關于軟件的復雜性問題,我做了一些思考:

    1) Cyclomatic Complexity (圈復雜性 = number of decision points +1    其中number of decision points是指一個if else之類的條件判斷語句 (引自《軟件的最大追求是什么》)

    if else 語句可以被行為模式/策略模式代替,不妨看下列的例子:

    假設我們要根據條件判斷來完成不同的行為,用if else 是這樣寫的:

    main() {

    if(case A){

    //do with strategy A

    }else(case B){

    //do with strategy B

    }else(case C){

    //do with strategy C

    }

    }



    用策略模式則如下:

    class runner{

    do();

    }



    class A extends runner{

    do(){

    //do with strategy A

    }

    }



    class B extends runner{

    do(){

    //do with strategy B

    }

    }



    class C extends runner {

    do(){

    //do with strategy C

    }

    }



    main(){

    runner.do();

    }



    用了策略模式后main()中的語句的確簡單多了,再也看不到該死的if else了^_^酷~~~



    可實際上是這樣簡單嗎???仔細研究一下上面的代碼就能看出問題出來,首先這兩段代碼中的A、B、C的實際意義是不一樣的:第一段代碼中ABC代表的是某一個邏輯條件的值而第二段中的ABC則是具體的類;第二段得到如此簡化的前提是它得到的邏輯條件就是一個類;如果得到的仍然只是一個邏輯條件,那么為了達到代碼簡化的效果,必須由另一個類(或方法)完成這種邏輯條件到具體類的轉換,會出現類似下列的代碼

    class RunnerFactory{

    runner getInstante(case){

    if (case A) return new A();

    else if (case B) return new B();

    else if (case C) return new C(); } }



    從測試的角度來說,兩者的測試分支都是3,復雜度相同,而第二種方法在很多的時候貌似還要測試借口的有效性。用策略模式還有一個缺點就是會使系統中的類的數量大大的增加,如上的例子,采用if else類的數量為1,而采用策略模式的類個數為5個或6個(主要取決于邏輯映射是否用單獨的類)。

    如果邏輯判斷的條件有三個,每個邏輯條件有三種可能的話,用策略模式系統至少會增加10個新類;如果條件更多的話類的個數也會更多 這么看來GOF的策略模式還要它干嘛??

    當然不是,策略模式在很多情況下是一種非常好的解決方案。

    這還要從if else 語句造成程序復雜以至難以維護的真正原因說起。就我個人的感覺真正造成if else語句難以維護的原因是每一個邏輯分支中的處理語句過長。比如我現在工作中維護的代碼,常常一個條件下面的業務處理語句有兩三千行,每次我光確定某個邏輯分支的結束位置就要找半天,頭暈-_-!。如果是多層條件的話情況就更糟了。一個分支就一千多行,幾個分支上萬行自然很難維護。 if else 語句本質上是程序的流程控制語句,而分支中N長的代碼通常是業務處理語句。

    行為模式/策略模式就是把流程判斷和業務處理進行了一次解耦,將業務邏輯封裝成一個個單獨的類。換句話說,行為模式/策略模式并不是不需要if else 語句(事實上該判斷的還是要判斷),只不過的換了地方或者是別的代碼幫你做了。另一方面,進行邏輯判斷的語句被集中起來而不是分散在程序的各個角落,有利于邏輯本身的維護。策略模式/行為模式還有一個明顯的好處就是如果新增加了一種狀態,我們只需要新增加一個策略類(同上的ABC)就可以了,避免了在程序中改動那些大段大段讓人厭煩的if else 語句。

    所以對于你的程序來說到底是使用設計模式還是簡單的使用if else 關鍵在于你的程序是否復雜,有沒有必要將控制邏輯和業務邏輯進行解耦。當然如果你可以用別的方式實現解耦也是非常好的。



    2) Response for Class(RFC) 當一個類和很多其他類存在依賴時,它就變得復雜甚至難以修改和維護,這樣,RFC值越大,表示你的系統味道越壞。(引自《軟件的最大追求是什么》)



    復雜性是由類與類之間的依賴關系(dependency)造成的。

    具體如下所示:

    interface Runner;

    class A implement runner{ do(){}; }



    一個大型的系統中很多地方用到了runner接口,于是在很多地方出現了如下的相同代碼:

    {

    Runner r = new A();

    r.do();

    }



    如果因為某種原因runner接口的實現類改為B,則在所有用到runner接口的地方代碼都要統統改為:

    {

    //Runner r = new A();

    Runner r = new B(); r.do();

    }



    這些遍布系統各個角落的改動是繁瑣且容易出錯的。

    于是出現了各種框架和模式,其中最著名的當然是IOC(Inversion of Control)反轉控制或者稱之為依賴型注射(Dependency Injection) 那些討厭的代碼變成了如下:

    {

    ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");

    Runner r = (Runner)ctx.getBean("Runner");

    r.do();

    }



    這樣我們就不需要對各個角落的代碼進行維護了,容器會自動的為我們選擇合適的類。

    我到覺得維護的工作還是我們的,為了讓容器注射入合適的類,我們必須要維護一個叫Spring.xml的配置文件,或者如果你不喜歡配置文件這個東東的話(比如偶)就得自己寫一個注冊類,將依賴關系一一注冊進去。你還要為使用該接口的類定義一個以該接口為參數的構造函數或者該接口的setter方法,好讓容器可以將實現類順利的注射進來。

    該做的還是要做,只不過換了一個地方做而已。但就是換了個地方,實現了對依賴關系的集中維護(又是集中),大大的改善了系統的結構,明確了不同職責單位之間的分工。呵呵,有時自己也極端的覺得設計的工作說到底就是解決代碼結構的問題^_^



    IOC一直是和輕量級框架聯系在一起的。所謂的重量級框架EJB也有實現相同功能的解決方案:Service Locator Service Locator就是一個定位器,它維護了一個數據結構(比如一個表),通過這個定位器你可以準確的定位到你的接口想要的實現類,Service Locator同樣使你免去了改變接口實現類后的維護惡夢:

    {

    Runner r = (Runner)ServiceLocator.lookup("Runner");

    r.do();

    }



    無論是IOC還是Service Locator都幫助你維護了類之間的依賴關系。那么是否我們在編程中一定要用呢,這又是個權衡的問題,IOC帶來了很多的好處,不過我個人認為它的代碼是讓人費解的(你根本不知道它做了什么),并且為了用它,一方面你要借助于容器,另一方面你要編寫配置文件,要為依賴型注射提供合適的途徑。

    如果你的系統類之間的依賴型錯綜復雜,需求的變化常常導致實現類的變化,同時你又希望采用測試驅動的快速開發模式,IOC毫無疑問是一個完美的解決方案;如果你的系統不存在上述的問題,為什么不簡簡單單的在程序中寫死呢,何苦去維護一堆配置文件(我所在的開發部門貌似都比較痛恨配置文件這個東東)。Service Locator也有很多缺點,被罵的最多的就是沒法快速測試。

    反轉控制,即轉換控制權。依賴關系控制權的轉換是對代碼結構的一次重構,重構的目標還是解耦,讓不同的職責代碼集中放到不同的地方,于是程序員可以更加專注的解決特定的問題,比如業務邏輯。

    程序設計的發展就是對代碼結構的不斷調整,不斷解耦,讓特定的代碼解決特定的問題而不是什么都混在一起。從面向過程到面向對象難道不是這樣嗎,封裝的本質也是解耦。



    在實際問題的解決當中,最重要的信條就是合適,要記住任何結構的改進都會付出代價,你的改進是否值得你為此付出的代價。比如當你做一個嵌入式程序的時候你首要考慮的自然是效率問題;而如果你做的是一個ERP產品,在系統設計的時候,光系統的可維護性問題就讓你不得不絞盡腦汁考慮一下代碼的結構。



    一句話,只做最對的。

    程序設計的最大追求就是在合適的地方做正確的事。

    posted on 2008-02-25 14:11 昨夜人生 閱讀(211) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲午夜久久久久久久久电影网 | 青青草国产免费国产是公开| 在线永久看片免费的视频| 国产亚洲精品岁国产微拍精品| 无套内谢孕妇毛片免费看看| 夜色阁亚洲一区二区三区| 国产啪亚洲国产精品无码| eeuss免费天堂影院| 国产亚洲精品福利在线无卡一| 一级片在线免费看| 久久久久亚洲AV成人网人人软件| 一级中文字幕乱码免费| 国产AⅤ无码专区亚洲AV| a级黄色毛片免费播放视频| 亚洲成a人片77777kkkk| 91人人区免费区人人| 亚洲综合免费视频| 久久精品网站免费观看| 亚洲精品无码mⅴ在线观看| 亚洲AV成人无码网天堂| 一个人免费日韩不卡视频| 国产一级一片免费播放i| 国产亚洲蜜芽精品久久| 久久久久噜噜噜亚洲熟女综合| 在线观看肉片AV网站免费| 亚洲欧洲日产国码www| 天天天欲色欲色WWW免费| 另类小说亚洲色图| 亚洲AV永久精品爱情岛论坛| **真实毛片免费观看| 亚洲国产成人精品无码区花野真一 | 日韩在线a视频免费播放| 亚洲免费在线观看视频| a级片免费在线播放| 亚洲精品国产专区91在线| 日韩a级毛片免费观看| 成全视成人免费观看在线看| 四虎亚洲国产成人久久精品| 全免费a级毛片免费看| 亚洲色中文字幕在线播放| a级亚洲片精品久久久久久久|