之前只是在各种博客和书籍上看到设计模式使用的理论知识,今天在项目中,正好遇到了这种需求,于是想着用这俩种模式实战一下,没想到成功了,记录一下,也欢迎各位大兄弟们继续给出好的建议。
需求:
有一个列表的数据,数据里有状态一栏,但是不同角色看到的状态值不一样。
原先处理方法:
对于各种新手小伙伴来说,是不是要各种if判断角色code,然后在不同的if里,去修改状态的文本值?类似于这样:
if(roleCodeConfig.getSSFAGLY().equals(roleCode)){
reqPageVo.setStatus("展示的数据");
}
if(roleCodeConfig.getYWBMGLY().equals(roleCode)){
reqPageVo.setStatus("展示的数据");
}
if(roleCodeConfig.getSSXJ().equals(roleCode)){
reqPageVo.setStatus("展示的数据");
}
if(roleCodeConfig.getZXGLY().equals(roleCode)){
reqPageVo.setStatus("展示的数据");
}
当遇到代码里根据某个字段的不同值去判断走不同逻辑的时候,我们就应该要想到是不是可以用工厂+策略的设计模式去解决这个问题。逐渐摈弃掉if,else的写法,这样我们才能再每次的一点点进步中逐渐提高嘛,博主也是在外包公司里,所以代码都得自己去摸索着优化,可参考的大神代码少之又少。下面进入正式的改造流程及思路。
改造之后:
1.首先要想到不同的角色都需要改这个状态,那将改状态这个单独拎出来,成为一个接口方法,然后各种角色的实现类,去实现这个方法。如下:
public interface StatusStrategy {
/**
* 展示数据
*/
List<DictValue> displayStatus();
}
2.然后有多少个角色去展示,就建多少个角色的实现类。
我这里有4个角色,所以新建了4个实现类,如图
每个实现类的代码如下:
@Component
public class BusinessAdminStrategy implements StatusStrategy {
@Override
public List<DictValue> displayStatus() {
List<DictValue> dictValues = initStatus();
//根据value过滤数据,是需要value为1,2,3的数据
return dictValues.stream().filter(dictValue -> SysCode.TEMPSTATUS.WAIT_APPLY.equals(dictValue.getValue())
|| SysCode.TEMPSTATUS.WAIT_EVALUATE.equals(dictValue.getValue())
|| SysCode.TEMPSTATUS.EVALUATED.equals(dictValue.getValue())).collect(Collectors.toList());
}
}
@Component
public class CarryOutAdminStrategy implements StatusStrategy {
@Override
public List<DictValue> displayStatus() {
List<DictValue> dictValues = initStatus();
//根据value过滤数据,是需要value为1,2,3的数据
return dictValues.stream().filter(dictValue -> SysCode.TEMPSTATUS.WAIT_APPLY.equals(dictValue.getValue())
|| SysCode.TEMPSTATUS.WAIT_EVALUATE.equals(dictValue.getValue())
|| SysCode.TEMPSTATUS.EVALUATED.equals(dictValue.getValue())).collect(Collectors.toList());
}
}
后面俩个都是类似的,就不一一列出了,在这实现类里,需要注意的也就注意下@Component这个注解,这个千万不能漏,漏完spring就找不到他的实例了。到这,策略模式应该是完成了,接下来就是把工厂模式加入进来了。
3.新建工厂类,将实现类的调用交给工厂来管理,代码如下:
@Component
public class StatusStrategyFactory {
private final Map<String, StatusStrategy> map = Maps.newHashMap();
@Autowired
public StatusStrategyFactory(List<StatusStrategy> statusStrategyList) {
for (StatusStrategy statusStrategy : statusStrategyList) {
map.put(statusStrategy.getClass().getName(), statusStrategy);
}
}
public StatusStrategy getStrategy(String strategyName) {
return map.get(strategyName);
}
}
解析下这个类里需要注意的地方:
1.还是@Component这个注解,这个和上面所说的内容一样。
2.map的作用,这个看代码应该能得知,就是为了将实现类做成一一映射关系,方便业务代码能通过key获取到对应的实现类。
3.@Autowird,这个注解一定要加哦,加完之后,map的键值对就会自动维护好,而不需要我们再逐一的去put操作。
到这里工厂模式+策略模式就相当于是已经搭建完成了。
4.最后在业务代码中进行调用就完事了,接下来给出具体的实例代码哈
首先,维护一个常量类(其实这里的魔法值也可以改为从配置文件或枚举类里获取,来保证所有的常量出口统一,小伙伴们可以自行去优化一下):
public class SysCode {
public static final Map<String, String> ROLECODE_IMPL =
new ImmutableMap.Builder<String, String>()
.put("leader", LeaderAdminStrategy.class.getName())
.put("business", BusinessAdminStrategy.class.getName())
.put("carryOut", CarryOutAdminStrategy.class.getName())
.put("center", CenterAdminStrategy.class.getName())
.build();
}
然后再业务代码里进行调用
到这就结束了,是不是代码一下就简洁了好多,而且也方便后期的维护,后续如果有新需求是根据不同角色来操作的话,是不是可以把方法写进策略的接口里,然后不同的角色实现类再去各自实现,就不同再写老多老多的ifelse了,即使新加了角色,我们也可以不用再改老代码,直接维护策略接口和新增新角色的实现类就行了,对吧。
结束:
觉得有用的小伙伴点个关注和喜欢一下吧,不定时会分享一些简单有用的编码小技巧,大神绕路,勿喷~~~