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

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

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

    隨筆-314  評論-209  文章-0  trackbacks-0

    大多數開發人員現在還在使用if else的過程結構,曾看過jdonbanq大哥寫的一篇文章,利用command,aop模式替代if else過程結構。當時還不太明白,這幾天看了《重構》第一章的影片租賃案例,感觸頗深。下面我來談一談為什么要用state pattern替代if else,替代if else有什么好處,以及給出詳細代碼怎么替代if else。本文參考jdon的“你還在使用if else嗎?”及《重構》第一章。

    ?

    首先我們模仿影片租賃過程,顧客租憑影片,影片分為兒童片、普通片、新片。根據影片類型及租憑天數價格各不相同(優惠程度不同),用戶累計積分不同。

    ?

    OK ,現在我們使用 if else 表示。

    package ?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:影片基類
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?15:47:55
    ?*?</p>
    ?*?
    ?*?
    @author ?EOMS?曲靜波
    ?*?
    @version ?1.0
    ?
    */

    public ? class ?Movie? {

    ?????
    // ?普通片標識
    ????? public ? static ? int ?REGULAR? = ? 1 ;
    ????
    ?????
    // ?新片標識
    ????? public ? static ? int ?NEW_RELEASE? = ? 2 ;
    ????
    ?????
    // ?兒童片標識
    ????? public ? static ? int ?CHILDREN? = ? 3 ;
    ????
    ?????
    /**
    ?????*?獲取租賃影片總價
    ?????*
    ?????*?
    @param ?movieCode
    ?????*?影片類型
    ?????*?
    @param ?days
    ?????*?租憑天數
    ?????*?
    @return ?租賃影片總價
    ?????*?
    @throws ?MovieException
    ?????*?沒有影片類型拋出異常
    ?????
    */

    ?????
    public ? double ?getCharge( int ?movieCode,? int ?days)? throws ?MovieException? {
    ?????
    double ?result? = ? 0 ;
    ?????
    // ?普通片
    ????? if ?(movieCode? == ?Movie.REGULAR)
    ?????
    // ?單價為2
    ????? {
    ?????result?
    = ? 2 ;
    ?????
    // ?如果租賃天數大于2則,則優惠
    ????? if ?(days? > ? 2 )? {
    ?????result?
    += ?(days? - ? 2 )? * ? 1.5 ;
    ?????}

    ?????
    // ?返回總價
    ????? return ?result;
    ?????}

    ?????
    // ?最新發布片
    ????? else ? if ?(movieCode? == ?Movie.NEW_RELEASE)? {
    ?????
    // ?新片沒有優惠,單價為3
    ????? return ?days? * ? 3 ;
    ?????}

    ?????
    // ?兒童片
    ????? else ? if ?(movieCode? == ?Movie.CHILDREN)? {
    ?????
    // ?影片單價
    ?????result? = ? 1.5 ;
    ?????
    // ?如果租賃時間大于3天則做價格優惠
    ????? if ?(days? > ? 3 )? {
    ?????result?
    += ?(days? - ? 3 )? * ? 1.5 ;
    ?????}

    ?????
    // ?返回租賃影片總價
    ????? return ?result;
    ?????}
    ? else
    ?????
    throw ? new ?MovieException( " 影片不存在 " );
    ?????}

    ????
    ?????
    /**
    ?????*?獲取租賃影片積分
    ?????*
    ?????*?
    @param ?movieCode
    ?????*?影片類型
    ?????*?
    @param ?days
    ?????*?租憑天數
    ?????*?
    @return ?租賃影片積分
    ?????*?
    @throws ?MovieException
    ?????*?沒有影片類型拋出異常
    ?????
    */

    ?????
    public ? double ?getIntegral( int ?movieCode,? int ?days)? throws ?MovieException
    ?????
    {
    ?????
    // ?普通片
    ????? if ?(movieCode? == ?Movie.REGULAR)
    ?????
    return ?days? * ? 2 ;
    ?????
    // ?最新發布片
    ????? else ? if ?(movieCode? == ?Movie.NEW_RELEASE)
    ?????
    return ?days? * ? 3 ;
    ?????
    // ?兒童片
    ????? else ? if ?(movieCode? == ?Movie.CHILDREN)
    ?????
    return ?days? * ? 1.5 ;
    ????????????
    else
    ????????????????
    throw ? new ?MovieException( " 影片不存在 " );
    ????
    ????????}

    }


    OK ,我們看一下,現在的 Movie 完全符合租賃需求,通過 getIntegral(int movieCode,int days) getCharge(int movieCode,int days) 來獲得租賃積分及租賃價格。從開閉原則角度來看,如果要添加新的影片類型,我們必須修改 getIntegral(int movieCode,int days) getCharge(int movieCode,int days) 這兩個方法。而若要改變租賃價格、積分的優惠規則時,仍需要修改 getIntegral(int movieCode,int days) getCharge(int movieCode,int days) 方法。現在看來,只有三種影片類型,維護還較方便。而當影片類型較多時,例如 10 種, 100 種影片類型,這樣就是不可以想像的維護。

    ?

    現在我們來看一下,使用 state pattern 來代替 if else 。先來個類圖。

    ?

    ifelse.jpg?

    首先我們建立一個 abstract class Price 做為影片類型的基類,基類中含有兩個 abstract 方法,獲取總價格 getCharge(int days), 獲取總積分 getIntegral(int days) 方法 , 繼承 abstract classPrice 的三個影片類型兒童片 class ChilerenPrice, 普通片 class RegularPrice, 最新片 class NewReleasePrice 。分別實現 getCharge(int days),getIntegral(int days) 方法,實現方法寫入計算價格的優惠方案及積分的方案。當需要修改方案時,我們只需在某個影片類的方法中對應修改就可以。若新增一個影片分類時,我們只需新增一個實現類實現 abstract class Price 類就 OK

    ?

    class Movie 代表影片,其關聯一個 Price 類,而 setPrice(String movieClass) 方法類似于一個工廠類,傳入 movieClass 為包名類名,用 java 反射機制實例化一個具體傳入 movieClass 的影片類型實現類,這樣我們通過這幾行代碼就可以獲得該影片類型的價格和積分。

    Movie?regularMovie? = ? new ?Movie();
    regularMovie.setPrice(Movie.REGULAR);
    System.out.println(
    " 普通影片租賃10天的價格 " + ?regularMovie.getPrice().getCharge( 10 ));
    System.out.println(
    " 普通影片租賃10天的積分 " + ?regularMovie.getPrice().getIntegral( 10 ));

    下面我們給出詳細代碼

    abstract class Price價格基類

    package?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?15:48:22
    ?*?</p>
    ?*?
    ?*?
    @author?EOMS?曲靜波
    ?*?
    @version?1.0
    ?
    */

    public?abstract?class?Price?{

    ????
    /**
    ?????*?獲取租賃影片價格需實現該此方法
    ?????*?
    ?????*?
    @param?days
    ?????*????????????租賃天數
    ?????*?
    @return?返回影片價格
    ?????
    */

    ????
    public?abstract?double?getCharge(int?days);

    ????
    /**
    ?????*?獲取租賃影片積分需實現此方法
    ?????*?
    ?????*?
    @param?days
    ?????*????????????租賃天數
    ?????*?
    @return?返回影片積分
    ?????
    */

    ????
    public?abstract?double?getIntegral(int?days);

    }



    兒童片ChildrenPrice類,實現abstract class Price ,實現兒童片租賃總價getCharge(int days)及兒童片租賃積分getIntegral(int days)
    package?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:兒童片租賃積分、價格實現
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?15:49:04
    ?*?</p>
    ?*?
    ?*?
    @author?EOMS?曲靜波
    ?*?
    @version?1.0
    ?
    */

    public?class?ChildrenPrice?extends?Price?{

    ????
    /**
    ?????*?兒童片返回租賃積分,兒童片積分規則為:?根據
    ?????
    */

    ????
    public?double?getIntegral(int?days)?{
    ????????
    //?返回租賃影片積分
    ????????return?days?*?1.5;
    ????}


    ????
    /**
    ?????*?兒童片返回租賃價格
    ?????
    */

    ????
    public?double?getCharge(int?days)?{
    ????????
    //?影片單價
    ????????double?result?=?1.5;
    ????????
    //?如果租賃時間大于3天則做價格優惠
    ????????if?(days?>?3)?{
    ????????????result?
    +=?(days?-?3)?*?1.5;
    ????????}

    ????????
    //?返回租賃影片總價
    ????????return?result;
    ????}


    }



    普通片RegularlPrice類,實現abstract class Price ,實現普通片租賃總價getCharge(int days)及普通片租賃積分getIntegral(int days)

    package?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:普通片租賃積分、價格實現
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?15:50:10
    ?*?</p>
    ?*?
    ?*?
    @author?EOMS?曲靜波
    ?*?
    @version?1.0
    ?
    */

    public?class?RegularlPrice?extends?Price?{
    ????
    /**
    ?????*?普通片返回租賃積分,普通片積分規則
    ?????
    */

    ????
    public?double?getIntegral(int?days)?{
    ????????
    //?返回租賃影片積分
    ????????return?days?*?2;
    ????}


    ????
    /**
    ?????*?普通片返回租賃價格
    ?????
    */

    ????
    public?double?getCharge(int?days)?{
    ????????
    //?單價為2
    ????????double?result?=?2;
    ????????
    //?如果租賃天數大于2則,則優惠
    ????????if?(days?>?2)?{
    ????????????result?
    +=?(days?-?2)?*?1.5;
    ????????}

    ????????
    //?返回總價
    ????????return?result;
    ????}


    }



    最新發布片
    NewReleasePrice類,實現abstract class Price ,實現最新發布片租賃總價getCharge(int days)及最新發布片租賃積分getIntegral(int days)

    package?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:最新發布片租賃積分、價格實現
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?15:48:51
    ?*?</p>
    ?*?
    ?*?
    @author?EOMS?曲靜波
    ?*?
    @version?1.0
    ?
    */

    public?class?NewReleasePrice?extends?Price?{
    ????
    /**
    ?????*?最新發布片返回租賃積分,最新發布片積分規則
    ?????
    */

    ????
    public?double?getIntegral(int?days)?{
    ????????
    //?返回租賃影片積分
    ????????return?days?*?3;
    ????}


    ????
    /**
    ?????*?最新發布片返回租賃價格
    ?????
    */

    ????
    public?double?getCharge(int?days)?{
    ????????
    //?新片沒有優惠,單價為3
    ????????return?days?*?3;
    ????}


    }



    電影Movie類,setPrice(String movieClass)(工廠)方法,通過java反射機制實現movieClass(包名,類名)類。若沒有movieClass這個類,則拋出MovieException異常。

    package?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:影片類
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?15:47:55
    ?*?</p>
    ?*?
    ?*?
    @author?EOMS?曲靜波
    ?*?
    @version?1.0
    ?
    */

    public?class?Movie?{
    ????
    //?普通片標識
    ????public?static?String?REGULAR?=?"com.qujingbo.movie.RegularlPrice";

    ????
    //?新片標識
    ????public?static?String?NEW_RELEASE?=?"com.qujingbo.movie.NewReleasePrice";

    ????
    //?兒童片標識
    ????public?static?String?CHILDREN?=?"com.qujingbo.movie.ChildrenPrice";

    ????
    private?Price?price;

    ????
    public?Price?getPrice()?{
    ????????
    return?price;
    ????}


    ????
    /**
    ?????*?確定返回具體某個影片類型的實現類,有點像工廠
    ?????*?
    ?????*?
    @param?movieCode
    ?????*????????????影片類型
    ?????*?
    @throws?MovieException
    ?????*?????????????若無影片類型則拋異常。
    ?????
    */

    ????
    public?void?setPrice(String?movieClass)?throws?MovieException?{
    ????????
    try?{
    ????????????Class?cls?
    =?Class.forName(movieClass);
    ????????????
    this.price?=?(Price)?cls.newInstance();
    ????????}
    ?catch?(Exception?e)?{
    ????????????
    throw?new?MovieException("影片不存在");
    ????????}

    ????}

    }



    給出MovieException源碼。

    package?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:自定義異常
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?19:21:08
    ?*?</p>
    ?*?
    ?*?
    @author?EOMS?曲靜波
    ?*?
    @version?1.0
    ?
    */

    public?class?MovieException?extends?Exception?{
    ????
    public?MovieException(String?msg)?{
    ????????
    super(msg);
    ????}

    }

    下面模訪一個顧客租賃影片。

    package?com.qujingbo.movie;

    /**
    ?*?<p/>?Title:
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?19:26:23
    ?*?</p>
    ?*?
    ?*?
    @author?EOMS?曲靜波
    ?*?
    @version?1.0
    ?
    */

    public?class?Customer?{
    ????
    /**
    ?????*?消費(測試程序)
    ?????*?
    ?????*?
    @throws?MovieException
    ?????*?????????????若沒有影片,拋出異常
    ?????
    */

    ????
    public?void?consume()?throws?MovieException?{
    ????????
    //?普通電影
    ????????Movie?regularMovie?=?new?Movie();
    ????????regularMovie.setPrice(Movie.REGULAR);
    ????????
    //?最新發布電影
    ????????Movie?newReleaseMovie?=?new?Movie();
    ????????newReleaseMovie.setPrice(Movie.NEW_RELEASE);
    ????????
    //?兒童電影
    ????????Movie?childrenMovie?=?new?Movie();
    ????????childrenMovie.setPrice(Movie.CHILDREN);

    ????????System.out.println(
    "普通影片租賃10天的價格"
    ????????????????
    +?regularMovie.getPrice().getCharge(10));
    ????????System.out.println(
    "最新影片租賃10天的價格"
    ????????????????
    +?newReleaseMovie.getPrice().getCharge(10));
    ????????System.out.println(
    "兒童影片租賃10天的價格"
    ????????????????
    +?childrenMovie.getPrice().getCharge(10));
    ????????
    ????????System.out.println(
    "普通影片租賃10天的積分"
    ????????????????
    +?regularMovie.getPrice().getIntegral(10));
    ????????System.out.println(
    "最新影片租賃10天的積分"
    ????????????????
    +?newReleaseMovie.getPrice().getIntegral(10));
    ????????System.out.println(
    "兒童影片租賃10天的積分"
    ????????????????
    +?childrenMovie.getPrice().getIntegral(10));
    ????????
    ????????
    ????}

    }


    寫一 junit 測試類運行 class Customer consume() 方法。

    package ?com.qujingbo.movie;

    import ?junit.framework.TestCase;

    /**
    ?*?<p/>?Title:junit測試類
    ?*?</p>
    ?*?<p/>?Description:
    ?*?</p>
    ?*?<p/>?Date:2006-10-14?19:32:57
    ?*?</p>
    ?*?
    ?*?
    @author ?EOMS?曲靜波
    ?*?
    @version ?1.0
    ?
    */

    public ? class ?CustomerTest? extends ?TestCase? {

    ????
    private ?Customer?customer? = ? null ;

    ????
    protected ? void ?setUp()? throws ?Exception? {
    ????????
    super .setUp();
    ????????customer?
    = ? new ?Customer();
    ????}


    ????
    protected ? void ?tearDown()? throws ?Exception? {
    ????????
    super .tearDown();
    ????}


    ????
    /*
    ?????*?Test?method?for?'com.qujingbo.movie.Customer.consume()'
    ?????
    */

    ????
    public ? void ?testConsume()? {
    ????????
    try ? {
    ????????????customer.consume();
    ????????}
    ? catch ?(MovieException?e)? {
    ????????????System.out.println(
    " 沒有該類影片 " );
    ????????}

    ????}


    }


    OK 。結果為:

    普通影片租賃 10 天的價格 14.0

    最新影片租賃 10 天的價格 30.0

    兒童影片租賃 10 天的價格 12.0

    普通影片租賃 10 天的積分 20.0

    最新影片租賃 10 天的積分 30.0

    兒童影片租賃 10 天的積分 15.0

    ?

    最后我要說,我們用 OO 表示的租賃過程并不完整,因為顧客不一定只租賃一部影片,而要租賃多部影片,這樣我們缺少一個 Rental (租賃類)。而只是為說明 state pattern 替代 if else ,所以我們沒有添加 Rental (租賃類),若需要參考,請查閱《重構》第一章。 點擊下載源碼.

    ?

    這是我第一次寫技術文章,如果有適當的地方,請各位朋友提出各自見解。

    posted on 2006-10-16 13:46 xzc 閱讀(3140) 評論(0)  編輯  收藏 所屬分類: Design
    主站蜘蛛池模板: 亚欧色视频在线观看免费| 亚洲欧洲日韩在线电影| 国产精品无码免费播放| 国产免费无码AV片在线观看不卡| 亚洲精品中文字幕| 亚洲一区二区三区在线观看蜜桃| 亚洲国产另类久久久精品小说 | 久久久久亚洲av毛片大| 免费无码黄网站在线观看| 91热久久免费精品99| a毛片免费观看完整| 人妻仑乱A级毛片免费看| 亚洲第一成年免费网站| 亚洲人成电影青青在线播放| 亚洲AV成人精品网站在线播放| 国产成人精品亚洲精品| 全部免费国产潢色一级| 日本免费网站在线观看| 在线成人a毛片免费播放| 91精品免费国产高清在线| 2019中文字幕在线电影免费| 久久久久久久岛国免费播放| 久久久精品免费国产四虎| 97无码人妻福利免费公开在线视频 | 相泽南亚洲一区二区在线播放| jiz zz在亚洲| 亚洲中文字幕无码中文字| 7777久久亚洲中文字幕| 最新亚洲春色Av无码专区| 亚洲精品午夜国产va久久| 国产AV旡码专区亚洲AV苍井空| 2020久久精品亚洲热综合一本| 亚洲 日韩 色 图网站| 亚洲国产视频久久| 亚洲熟妇无码八V在线播放| 亚洲欧美自偷自拍另类视| 日韩亚洲人成网站| 一区二区视频免费观看| 三级黄色免费观看| 香蕉免费一区二区三区| 国内精自视频品线六区免费|