前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【项目实战】去除繁琐的if..else 优雅使用策略模式

【项目实战】去除繁琐的if..else 优雅使用策略模式

作者头像
小东啊
发布2019-06-26 15:15:30
1.1K0
发布2019-06-26 15:15:30
举报
文章被收录于专栏:李浩东的博客李浩东的博客

项目需求

最新开发系统权限管理系统时,有这样一个需求,不同角色的数据权限不一样需要做处理 根据数据范围拥有不同部门的数据查看权限, 比如这样

代码语言:javascript
复制
if (全部) {获取全部部门ids} else if (本级) {
当前用户部门id} else if (本金以及子级) {
当前用户部门以及子部门ids} else {
自定义的部门ids
}

目前只是4层,虽然这样容易理解,逻辑清晰,但是虽然系统的拓展,if...else太多,这个就很可怕了。 因此使用策略模式来消除掉if else。

策略模式是一种解耦的方法,它对算法进行封装,使得算法的调用和算法本身分离。使用策略模式客户端代码不需要调整,算法之间可以互相替换,因为不同的算法实现的是同一个接口。将上面的代码优化后变为:

代码语言:javascript
复制
@Autowiredprivate DataScopeContext dataScopeContext;// 根据数据权限范围查询直接通过同一个dohandler方法根据不同的tag去选择处理不同的逻辑部门idsList<Integer> ids = dataScopeContext.getDeptIdsForDataScope(roleDto, roleDto.getDsType());

用户在选择不同数据范围时,由context上下文进行判断选择资源去资源池调用,直接通过同一个getDeptIdsForDataScope方法根据不同的类型去选择处理不同的逻辑,从而实现结构上的优化。 具体逻辑就是: 定一个策略handler接口,然后各个策略类去实现这个handler接口,并实现处理逻辑。 然后定一个定义策略上下文,通过Spring将实现Strategy的实现类都自动注入到strategyMap类中,根据type获取对应的策略 代码展示: 策略接口AbstractDataScopeHandler类

代码语言:javascript
复制
/** * @Classname AbstractDataScopeHandler * @Description 创建抽象策略角色 主要作用 数据权限范围使用 * @Author Created by Lihaodong (alias:小东啊) lihaodongmail@163.com * @Date 2019-06-08 15:45 * @Version 1.0 */
public interface AbstractDataScopeHandler {
    /**     * @param roleDto     * @param dataScopeTypeEnum     * @return     */    List<Integer> getDeptIds(RoleDTO roleDto, DataScopeTypeEnum dataScopeTypeEnum);}

策略类实现这个策略接口(只展现一种)

代码语言:javascript
复制
package com.xd.pre.strategy;
import com.xd.pre.constant.DataScopeTypeEnum;import com.xd.pre.domain.SysDept;import com.xd.pre.dto.RoleDTO;import com.xd.pre.service.ISysDeptService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;
import java.util.List;import java.util.stream.Collectors;
/** * @Classname AllDataScope * @Description 所有 * @Author Created by Lihaodong (alias:小东啊) lihaodongmail@163.com * @Date 2019-06-08 16:27 * @Version 1.0 */@Component("1")public class AllDataScope implements AbstractDataScopeHandler {
    @Autowired    private ISysDeptService deptService;
    // 执行逻辑    @Override    public List<Integer> getDeptIds(RoleDTO roleDto, DataScopeTypeEnum dataScopeTypeEnum) {        List<SysDept> sysDepts = deptService.list();        return sysDepts.stream().map(SysDept::getDeptId).collect(Collectors.toList());    }}

Service注入策略集合,根据type获取对应的策略

代码语言:javascript
复制
package com.xd.pre.strategy;
import com.xd.pre.constant.DataScopeTypeEnum;import com.xd.pre.dto.RoleDTO;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.List;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;
/** * @Classname DataScopeContext * @Description 创建环境角色Context: * @Author Created by Lihaodong (alias:小东啊) lihaodongmail@163.com * @Date 2019-06-08 16:11 * @Version 1.0 */@Servicepublic class DataScopeContext {
    @Autowired    private final Map<String, AbstractDataScopeHandler> strategyMap = new ConcurrentHashMap<>();
    /**     * Component里边的1是指定其名字,这个会作为key放到strategyMap里     * @param strategyMap     */    public DataScopeContext(Map<String, AbstractDataScopeHandler> strategyMap) {        strategyMap.forEach(this.strategyMap::put);    }
    public List<Integer> getDeptIdsForDataScope(RoleDTO roleDto, Integer type) {        return strategyMap.get(String.valueOf(type)).getDeptIds(roleDto, DataScopeTypeEnum.valueOf(type));    }}

服务层调用getDeptIdsForDataScope方法

通过这个,就可以看到通过在不同的类型获取不同部门ids,可以自动的拿到不同的资源。

使用策略模式的好处就是通过一个封装的上下文可以自由的切换不同的算法,省去多重判断,同时可以具有很好的扩展性。

当策略过多的时候就会显得很臃肿,建议大家合理的运用设计模式 具体的项目实战可以参考我的开源项目进行理解:

项目地址: https://gitee.com/li_haodong/pre

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 李浩东的博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目需求
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档