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

项目需求

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

if (全部) {	
获取全部部门ids	
} else if (本级) {	
当前用户部门id	
} else if (本金以及子级) {	
当前用户部门以及子部门ids	
} else {	
自定义的部门ids	
}

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

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

@Autowired	
private DataScopeContext dataScopeContext;	
// 根据数据权限范围查询直接通过同一个dohandler方法根据不同的tag去选择处理不同的逻辑部门ids	
List<Integer> ids = dataScopeContext.getDeptIdsForDataScope(roleDto, roleDto.getDsType());

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

/**	
 * @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);	
}

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

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获取对应的策略

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	
 */	
@Service	
public 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方法

640?wx_fmt=png

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

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

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

640?wx_fmt=png

640?wx_fmt=png

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

640?wx_fmt=png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值