在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    快速云:需求決定設(shè)計 面向?qū)ο笞畲蟮脑O(shè)計陷阱

    快速云:需求決定設(shè)計 面向?qū)ο笞畲蟮脑O(shè)計陷阱

    通過面向?qū)ο蟮乃悸?,我們可以把任何事物都看成一個對象然后單獨處理,從理想的角度,任何一個微小的單元都可以以一個對象的形式表示。比如我們可以用如下代碼表示一個人以及它的姓名

      1.不分離姓名

    class 人 {

    public string 姓名;

    }  但是這個世界是很復(fù)雜的,姓名本身是由姓和名組成的。如果我們需要需要單獨處理姓和名時,要怎么辦?于是我們可以這么拆分:

      2.直接分離姓名

    class 人 {

    public string 姓; public string 名;

    }  但我們會碰到這個問題:姓和名本身是一個整體,處理姓名的邏輯不應(yīng)該放在人這個類里面,而應(yīng)該單獨提取出來。于是代碼改為:

      3. 提取姓名為單獨一個類,然后單獨處理

    class 人 {

    public 姓名 姓名;

    }

    class 姓名 { public string 姓; public string 名;

    }  這是一個非常理想的狀態(tài):任何事物都被表示成了一個獨立的對象。但其實作者都是懶的,沒人會愿意為姓名單獨寫一個類然后單獨處理它。除非邏輯非常復(fù)雜需要單獨處理時,才會選擇把它提取出來。

      同樣一個人,把它寫成面向?qū)ο蟮拇a之后,卻有3種不同的寫法(1. 不分離姓名。 2. 直接分離姓名。 3.提取姓名為單獨一個類,然后單獨處理)。而決定我們用哪個寫法的是最需求。需求是軟件開發(fā)中最不穩(wěn)定的因素,因此面向?qū)ο蟮拇a經(jīng)常需要重構(gòu)和重寫。這就是面向?qū)ο笾械囊粋€設(shè)計陷阱。

      再來看一個例子:

    abstract class 魚 {private int 價格; private int 口感;public int get價格(){ return 價格; } public int get口感(){ return 口感; } public abstract string get名字();}

    class 鯉魚: 魚 { public override string get名字() { return “鯉魚”; }}

    class 桂魚: 魚 {  public override string get名字() { return “桂魚”;  }}  這是一個最普通的面向?qū)ο蟮拇a了。從上面看似乎完美到?jīng)]有任何問題:通過魚這個類以及它的多態(tài)特性,我們可以很輕松地處理所有魚。

      但是這時加了一個需求,我們需要處理金魚,于是寫了這么一行代碼:

    class 金魚: 魚 {  public override string get名字() { return “金魚”;  }}  看上去依然完美,但問題是:金魚是不能吃的,獲取它的口感是沒有任何意義的!但是通過繼承,我們的金魚也是可以有口感的。同時,還浪費了一個內(nèi)存用來存儲這個沒有意義的口感字段。

      現(xiàn)實中,很多人都忽視了這個問題:反正沒意義,這個函數(shù)不要調(diào)用就行了。對的,但如果一個繼承了一個父類之后,5個函數(shù)是有意義的,20個函數(shù)是沒有意義的,這時我想作者該犯潔癖了吧。問題主要是在于繼承一個類之后,有一些成員是不必要或者無意的,有2個改法:

      1. 讓金魚不繼承于魚:這不科學(xué),金魚本來就是魚,除了口感,其它的繼承都是有意義并且需要使用的。

      2. 提取一個公共父類:

    abstract class 魚 { private int 價格; public int get價格(){ return 價格; } public virtual int get口感() { throw new Exception(“無意義”) } public abstract string get名字();}

    abstract class 可以吃的魚 : 魚 { private int 口感; public override int get口感() { return 口感; }}

    class 鯉魚: 可以吃的魚 { public override string get名字() { return “鯉魚”; }}

    class 桂魚: 可以吃的魚 {  public override string get名字() { return “桂魚”;  }}

    class 金魚: 魚 {  public override string get名字() { return “金魚”;  }}  仔細(xì)研究,你會發(fā)現(xiàn)網(wǎng)上很多代碼,它定義了一個抽象類,并且名字是 XXXBase, XXXCore 或者一個類XXX還定義了一個類叫 XXXImpl 。這些抽象類就像上例中可以吃的魚這個類一樣,都是為了繼承而存在的。這里,我們同樣有這個問題:

      父類的設(shè)計會因為需求和子類的增加和不得不作一些修改(如提取另外一個公共父類)。因此面向?qū)ο蟮拇a經(jīng)常需要重構(gòu)和重寫。這就是面向?qū)ο笾械挠忠粋€設(shè)計陷阱。

      總結(jié)一下上面的2個例子,就是:需求增加,代碼就要重構(gòu)。所以很多人認(rèn)為這是一個只能靠經(jīng)驗才能解決的問題,只要寫的代碼夠多了,就能預(yù)感到未來的需求并減少重構(gòu)量。就像上例中,我們有經(jīng)驗就會先寫好一個可以吃的魚這個類。但這終究是一個幻想,沒有誰能真正預(yù)知到未來的需求。很多作者都喜歡預(yù)留一個XXX接口,然后寫了一個XXXImpl的實現(xiàn)類,認(rèn)為以后只寫另外一個XXXImpl2類,就可以重用處理XXX接口時的所有代碼。其實以后需要寫另外一個XXXImpl2類的概率幾乎為0 。這樣反而讓修改XXX接口的成本上升不少。

      需求決定設(shè)計,需求變化會導(dǎo)致不斷重新設(shè)計。這就是面向?qū)ο蟮淖畲笤O(shè)計陷阱。

    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
    上一篇 2022年6月27日 15:06
    下一篇 2022年6月27日 15:07

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時間:周一至周五,10:30-18:30,節(jié)假日休息