本系列文章不关注设计模式的理论,侧重于怎么把设计模式用在实际的业务场景中。
需求背景
最近接到一个业务需求,大概业务流程是这样:
user state分析下这个需求:
- 分别代表5中用户状态,UnActiveState,normalSate,freezeState,deleteSate..
- 根据业务规则,5中状态之间可以相互转换。(箭头所示)
- 状态不能转换到自己。
最常规的编码方式:
// 伪代码
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;
}
.....
上述的代码存在几个问题。非常难以维护的,而且完全没什么逻辑可言,每个状态之间耦合非常严重。另外,阿里巴巴java规范也告诉每个程序员,要少写复杂的if逻辑判断。否则就应该检查开发自己的逻辑思维。
接下来,我们用转台模式来实现这个业务功能:
用状态模式实现
定义每一个状态类
定义用户状态的基类,把所有状态允许的切换操作(箭头流向)定义为方法。(eg.未激活 - 正常 定义为active())
/**
* @description: 抽象所有用户状态操作,默认都不允许。让子类去复写
* @author: DENGHUANQING1
* @create: 2019-03-08 19:16
**/
public class UserState {
/**
* 激活
*
* @param user
* @return
*/
public Integer active(SysUserEntity user){
throw new BusinessException("用户状态不允许此操作");
};
/**
* 冻结
*
* @param user
* @return
*/
public Integer freeze(SysUserEntity user){
throw new BusinessException("用户状态不允许此操作");
};
/**
* 解冻
* @param user
* @return
*/
public Integer unfreeze(SysUserEntity user){
throw new BusinessException("用户状态不允许此操作");
};
/**
* 申诉成功
* @param user
* @return
*/
public Integer applySuc(SysUserEntity user){
throw new BusinessException("用户状态不允许此操作");
};
/**
* 删除:默认状态都允许删除
* @param user
* @return
*/
public Integer delete(SysUserEntity user){
return UserStatusEnum.DELETE.getValue();
};
}
把用户的每一个状态定义为单独的状态类,每个状态类继承UserState。实现可以操作的方法,即允许的数据流向。
未激活状态,只允许激活操作和删除操作:
/**
* @description:
* @author: DENGHUANQING1
* @create: 2019-03-09 21:06
**/
public class UnActiveState extends UserState {
@Override
public Integer active(SysUserEntity user) {
return UserStatusEnum.ACTIVED.getValue();
}
}
正常状态只允许冻结操作和删除操作:
/**
* @description:
* @author: DENGHUANQING1
* @create: 2019-03-09 21:07
**/
public class NormalSate extends UserState {
@Override
public Integer freeze(SysUserEntity user) {
return UserStatusEnum.FROZEN.getValue();
}
}
.......
定义完所有的状态后,对于单独的状态,程序只用关注此状态能做什么操作。这里由于每个状态能实现的操作远远小于所有的操作。所以UserState并没有定义为抽象类。大家可以根据自己需求定制。UserState类对默认无法通过的操作抛出的自定义的业务异常。
抽象用户的请求
接受前端的用户请求,需要做两件事情。
- 判断当前用户的状态
- 判断用户即将切换的状态是属于上面定义的那种操作(UserState的方法)
public class UserServiceImpl implements UserService {
@Override
public Integer switchState(SysUserEntity user, int state) {
if (user.getState() == state) {
// 用户状态不需要修改
return user.getState();
}
//判断当前用户的状态
UserState userState = UserStateContext.getUserSate(user);
MixcAsserts.isNotNull(userState, "用户状态不允许此操作");
// 判断用户的操作并且执行操作【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("用户状态不允许此操作");
}
}
}
静态工厂获取当前用户状态:
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;
}
}
总结
整体通过状态模式改造下来,我们的代码逻辑看起来清爽了很多,对于维护的同学来说也许会更明确一点。在【1】处其实也是做了很多的判断,目前没有想到比较优雅的实现方式。欢迎大家指点。
网友评论