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

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

需求背景

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

user state

分析下這個需求:

  • 分別代表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;
}
.....

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

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

定義每一個狀態(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();
    };
}

把用戶的每一個狀態(tài)定義為單獨(dú)的狀態(tài)類,每個狀態(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)后,對于單獨(dú)的狀態(tài),程序只用關(guān)注此狀態(tài)能做什么操作。這里由于每個狀態(tài)能實(shí)現(xiàn)的操作遠(yuǎn)遠(yuǎn)小于所有的操作。所以UserState并沒有定義為抽象類。大家可以根據(jù)自己需求定制。UserState類對默認(rèn)無法通過的操作拋出的自定義的業(yè)務(wù)異常。

抽象用戶的請求

接受前端的用戶請求,需要做兩件事情。

  • 判斷當(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é)

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容