本系列文章不關(guān)注設(shè)計(jì)模式的理論查蓉,側(cè)重于怎么把設(shè)計(jì)模式用在實(shí)際的業(yè)務(wù)場(chǎng)景中。
需求背景
最近接到一個(gè)業(yè)務(wù)需求椎椰,大概業(yè)務(wù)流程是這樣:
分析下這個(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)芒粹。