設(shè)計(jì)模式實(shí)戰(zhàn):01.狀態(tài)設(shè)計(jì)模式

本系列文章不關(guān)注設(shè)計(jì)模式的理論查蓉,側(cè)重于怎么把設(shè)計(jì)模式用在實(shí)際的業(yè)務(wù)場(chǎng)景中。

需求背景

最近接到一個(gè)業(yè)務(wù)需求椎椰,大概業(yè)務(wù)流程是這樣:

user state

分析下這個(gè)需求:

  • 分別代表5中用戶狀態(tài)哺呜,UnActiveState,normalSate瓣距,freezeState黔帕,deleteSate..
  • 根據(jù)業(yè)務(wù)規(guī)則,5中狀態(tài)之間可以相互轉(zhuǎn)換蹈丸。(箭頭所示)
  • 狀態(tài)不能轉(zhuǎn)換到自己成黄。
    最常規(guī)的編碼方式:
// 偽代碼
boolean result =false
private UserState cur;
private UserState target;
if((cur=UnActiveState & target=normalSate)||(cur=UnActiveState & target=deleteSate)){
  result =true;
}else if((cur=normalSate& target=freezeState)||(cur=normalSate& target=deleteSate)){
  result =true;
}
.....

上述的代碼存在幾個(gè)問(wèn)題。非常難以維護(hù)的逻杖,而且完全沒(méi)什么邏輯可言奋岁,每個(gè)狀態(tài)之間耦合非常嚴(yán)重。另外荸百,阿里巴巴java規(guī)范也告訴每個(gè)程序員闻伶,要少寫復(fù)雜的if邏輯判斷。否則就應(yīng)該檢查開(kāi)發(fā)自己的邏輯思維管搪。
接下來(lái)虾攻,我們用轉(zhuǎn)臺(tái)模式來(lái)實(shí)現(xiàn)這個(gè)業(yè)務(wù)功能:

用狀態(tài)模式實(shí)現(xiàn)

定義每一個(gè)狀態(tài)類

定義用戶狀態(tài)的基類,把所有狀態(tài)允許的切換操作(箭頭流向)定義為方法更鲁。(eg.未激活 - 正常 定義為active())

/**
 * @description: 抽象所有用戶狀態(tài)操作霎箍,默認(rèn)都不允許。讓子類去復(fù)寫
 * @author: DENGHUANQING1
 * @create: 2019-03-08 19:16
 **/
public class UserState {
    /**
     * 激活
     *
     * @param user
     * @return
     */
    public Integer active(SysUserEntity user){
        throw new BusinessException("用戶狀態(tài)不允許此操作");
    };

    /**
     * 凍結(jié)
     *
     * @param user
     * @return
     */
    public Integer freeze(SysUserEntity user){
        throw new BusinessException("用戶狀態(tài)不允許此操作");
    };

    /**
     * 解凍
     * @param user
     * @return
     */
    public Integer unfreeze(SysUserEntity user){
        throw new BusinessException("用戶狀態(tài)不允許此操作");
    };


    /**
     * 申訴成功
     * @param user
     * @return
     */
    public Integer applySuc(SysUserEntity user){
        throw new BusinessException("用戶狀態(tài)不允許此操作");
    };

    /**
     * 刪除:默認(rèn)狀態(tài)都允許刪除
     * @param user
     * @return
     */
    public Integer delete(SysUserEntity user){
        return UserStatusEnum.DELETE.getValue();
    };
}

把用戶的每一個(gè)狀態(tài)定義為單獨(dú)的狀態(tài)類澡为,每個(gè)狀態(tài)類繼承UserState漂坏。實(shí)現(xiàn)可以操作的方法,即允許的數(shù)據(jù)流向。
未激活狀態(tài)顶别,只允許激活操作和刪除操作:

/**
 * @description:
 * @author: DENGHUANQING1
 * @create: 2019-03-09 21:06
 **/
public class UnActiveState extends UserState {
    @Override
    public Integer active(SysUserEntity user) {
        return UserStatusEnum.ACTIVED.getValue();
    }
}

正常狀態(tài)只允許凍結(jié)操作和刪除操作:

/**
 * @description:
 * @author: DENGHUANQING1
 * @create: 2019-03-09 21:07
 **/
public class NormalSate extends UserState {
    @Override
    public Integer freeze(SysUserEntity user) {
        return UserStatusEnum.FROZEN.getValue();
    }
}

.......
定義完所有的狀態(tài)后谷徙,對(duì)于單獨(dú)的狀態(tài),程序只用關(guān)注此狀態(tài)能做什么操作驯绎。這里由于每個(gè)狀態(tài)能實(shí)現(xiàn)的操作遠(yuǎn)遠(yuǎn)小于所有的操作完慧。所以UserState并沒(méi)有定義為抽象類。大家可以根據(jù)自己需求定制剩失。UserState類對(duì)默認(rèn)無(wú)法通過(guò)的操作拋出的自定義的業(yè)務(wù)異常屈尼。

抽象用戶的請(qǐng)求

接受前端的用戶請(qǐng)求,需要做兩件事情拴孤。

  • 判斷當(dāng)前用戶的狀態(tài)
  • 判斷用戶即將切換的狀態(tài)是屬于上面定義的那種操作(UserState的方法)
public class UserServiceImpl implements UserService {
    @Override
    public Integer switchState(SysUserEntity user, int state) {
        if (user.getState() == state) {
            // 用戶狀態(tài)不需要修改
            return user.getState();
        }
      //判斷當(dāng)前用戶的狀態(tài)
        UserState userState = UserStateContext.getUserSate(user);
        MixcAsserts.isNotNull(userState, "用戶狀態(tài)不允許此操作");

    // 判斷用戶的操作并且執(zhí)行操作【1】
        if (user.getState() == 0 && state == 1) {
            // 激活用戶
            return userState.active(user);
        } else if (user.getState() == 1 && state == 2) {
            return userState.freeze(user);
        } else if (user.getState() == 2 && state == 1) {
            return userState.unfreeze(user);
        } else if (user.getState() != 4 && state == 4) {
            return userState.delete(user);
        } else {
            throw new BusinessException("用戶狀態(tài)不允許此操作");
        }
    }
}

靜態(tài)工廠獲取當(dāng)前用戶狀態(tài):

public class UserStateContext {
    private static UserState unActiveState;
    private static UserState normalSate;
    private static UserState freezeState;

    static {
        unActiveState = new UnActiveState();
        normalSate = new NormalSate();
        freezeState = new FreezeState();
    }

    public static UserState getUserSate(SysUserEntity entity) {
        switch (entity.getState()) {
            case 0:
                return unActiveState;
            case 1:
                return normalSate;
            case 2:
                return freezeState;
        }
        return null;
    }
}

總結(jié)

整體通過(guò)狀態(tài)模式改造下來(lái)脾歧,我們的代碼邏輯看起來(lái)清爽了很多,對(duì)于維護(hù)的同學(xué)來(lái)說(shuō)也許會(huì)更明確一點(diǎn)演熟。在【1】處其實(shí)也是做了很多的判斷鞭执,目前沒(méi)有想到比較優(yōu)雅的實(shí)現(xiàn)方式。歡迎大家指點(diǎn)芒粹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兄纺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子是辕,更是在濱河造成了極大的恐慌囤热,老刑警劉巖猎提,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件获三,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡锨苏,警方通過(guò)查閱死者的電腦和手機(jī)疙教,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)伞租,“玉大人贞谓,你說(shuō)我怎么就攤上這事】” “怎么了裸弦?”我有些...
    開(kāi)封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)作喘。 經(jīng)常有香客問(wèn)我理疙,道長(zhǎng),這世上最難降的妖魔是什么泞坦? 我笑而不...
    開(kāi)封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任窖贤,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赃梧。我一直安慰自己滤蝠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布授嘀。 她就那樣靜靜地躺著物咳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蹄皱。 梳的紋絲不亂的頭發(fā)上所森,一...
    開(kāi)封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音夯接,去河邊找鬼焕济。 笑死,一個(gè)胖子當(dāng)著我的面吹牛盔几,可吹牛的內(nèi)容都是我干的晴弃。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼逊拍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼上鞠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起芯丧,我...
    開(kāi)封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤芍阎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后缨恒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谴咸,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年骗露,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了岭佳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡萧锉,死狀恐怖珊随,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柿隙,我是刑警寧澤叶洞,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站禀崖,受9級(jí)特大地震影響衩辟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帆焕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一惭婿、第九天 我趴在偏房一處隱蔽的房頂上張望不恭。 院中可真熱鬧,春花似錦财饥、人聲如沸换吧。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沾瓦。三九已至,卻和暖如春谦炒,著一層夾襖步出監(jiān)牢的瞬間贯莺,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工宁改, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缕探,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓还蹲,卻偏偏與公主長(zhǎng)得像爹耗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谜喊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,113評(píng)論 1 32
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 11,007評(píng)論 6 13
  • 長(zhǎng)夜的燈火潭兽,還是那般,昏昏黃黃 哪一家的貓醒了斗遏,跳進(jìn)了那扇半開(kāi)的窗 仿佛還在昨夜的夢(mèng)里山卦,睜眼,依稀如常 直到手里有...
    且溯丶閱讀 252評(píng)論 2 2
  • 象曰 隨風(fēng)诵次,巽账蓉。君子以申命行事。 (柔而濟(jì)之以剛藻懒,則心之所之者有定見(jiàn)剔猿,事之所行者有定守!不持疑于兩可嬉荆,所系匪輕,必...
    傳統(tǒng)文化咀嚼者閱讀 296評(píng)論 0 0