小菜鸟程序员

教你如何使用策略模式

2021-01-15  本文已影响0人  我是一颗小虎牙_

策略模式

在策略模式中一个类的行为或者其算法在运行是可以进行改变,这种的类型也可以叫做行为型模式。

基本结构

优缺点

优点

缺点

场景

实例场景

今天和朋友要去公园玩儿,那么就要选择出行方式,那么创建一个出行的接口,创建自行车、公交、步行等行为类,并且都继承出行的接口,再创建我的选择类(Context)来选择出行方式。至此大体完成。

代码

出行方式接口

/**
 * @author Surpass
 * @Package com.hkrt.demo
 * @Description: 出行方式(工具)
 * @date 2021/1/15 16:16
 */
public interface Strategy {

    void goOutTool();
}

出行方式实现类

公交车

/**
 * @author Surpass
 * @Package com.hkrt.demo.strategy
 * @Description: 公交车
 * @date 2021/1/15 16:20
 */
public class BusWayStrategy implements Strategy{

    @Override
    public void goOutTool() {
        System.out.println("今天坐公交车出去玩儿");
    }
}

步行

/**
 * @author Surpass
 * @Package com.hkrt.demo.strategy
 * @Description: 步行方式
 * @date 2021/1/15 16:19
 */
public class WalkWayStrategy implements Strategy {

    @Override
    public void goOutTool() {
        System.out.println("今天要步行出去玩儿");
    }
}

自己开车

/**
 * @author Surpass
 * @Package com.hkrt.demo.strategy
 * @Description: 开车
 * @date 2021/1/15 16:21
 */
public class CarWayStrategy implements Strategy {

    @Override
    public void goOutTool() {
        System.out.println("今天自己开车出去玩儿");
    }
}

出行方式上下文

/**
 * @author Surpass
 * @Package com.hkrt.demo.strategy
 * @Description: 选择行为(上下文)
 * @date 2021/1/15 16:22
 */
public class StrategyContext {

    private Strategy strategy;

    public StrategyContext(Strategy strategy) {
        this.strategy = strategy;
    }

    public void goOut(){
        strategy.goOutTool();
    }
}

测试类

/**
 * @author Surpass
 * @Package com.hkrt.demo.strategy
 * @Description: 我和朋友准备出去玩儿
 * @date 2021/1/15 16:24
 */
public class PlayTest {
    public static void main(String[] args) {

        /**
         * 选择步行出去玩儿
         */
        StrategyContext walkWayStrategy = new StrategyContext(new WalkWayStrategy());
        walkWayStrategy.goOutTool();

        /**
         * 选择坐公交出去玩儿
         */
        StrategyContext busWayStrategy = new StrategyContext(new BusWayStrategy());
        busWayStrategy.goOutTool();

        /**
         * 选择自己开车出去玩儿
         */
        StrategyContext carWayStrategy = new StrategyContext(new CarWayStrategy());
        carWayStrategy.goOutTool();

    }
}

执行结果

Connected to the target VM, address: '127.0.0.1:11631', transport: 'socket'
今天要步行出去玩儿
今天坐公交车出去玩儿
今天自己开车出去玩儿
Disconnected from the target VM, address: '127.0.0.1:11631', transport: 'socket'

这样一个简单的策略就是出来了,如果出现新增的策略,只需要实现公共的出行方式接口,然后写自己的逻辑就OK了。

SpringBoot中应用

接了个需求,对接第三方接口进行数据的校验,每一个第三方都是一套规范,考虑到后续的可扩展性,和内部的统一,使用策略类进行实现。

在这里我去掉了Context上下文,直接在逻辑代码中注入校验接口,根据配置中的第三方数据的 channelCode 判断走哪个第三方接口( channelCode的值就是该第三方接口类在Spring中的beanName)。

校验接口

public interface BusinessAuthChannelService {

    /**
     *   企业信息要素验证
     * @param dto 校验数据
     * @return java.util.Map<java.lang.String , java.lang.Object>
     * @throws
     * @author Surpass
     * @date 2021/1/7 15:56
     */
    Map<String, Object> auth(AuthChannelDto dto);
}

第三方校验实现类(业务代码不便展示)

@Slf4j
@Service("qcc")
public class QccAuthChannelServiceImpl implements BusinessAuthChannelService {

    private Gson gson = new Gson();

    /**
     *  鉴权查询
     * @param dto
     * @return java.util.Map<java.lang.String , java.lang.Object>
     * @throws
     * @author Surpass
     * @date 2021/1/11 13:51
     */
    @Override
    public Map<String, Object> auth(AuthChannelDto dto) {
        Map<String, Object> resultMap = new HashMap<>();
        return resultMap;
    }
}

校验接口控制层

@Slf4j
@RestController
@RequestMapping("/businessAuthChannel")
public class BusinessAuthChannelController {

    @Autowired
    private BusinessAuthChannelConfigService businessAuthChannelConfigService;

    @Autowired
    private BusinessAuthChannelOrderService businessAuthChannelOrderService;

    private Gson gson = new Gson();

    /**
     *   企业信息要素验证
     * @param dto
     * @return java.util.Map<java.lang.String , java.lang.Object>
     * @throws
     * @author Surpass
     * @date 2021/1/7 15:38
     */
    @RequestMapping("/auth")
    public Map<String,Object> auth(@RequestBody AuthChannelDto dto){
        log.info("企业信息要素验证,要素鉴权参数:"+gson.toJson(dto));
        Map<String, Object> map = new HashMap<>(2);
        Map<String, Object> authResult = null;
        //校验参数
        boolean validateParameter = this.validateParameter(dto);
        if (!validateParameter){
            map.put("rspCode", "99");
            map.put("rspMsg", "参数校验失败");
            log.info("企业信息要素验证,返回数据:"+map);
            return map;
        }

        //查询鉴权通道
        BusinessAuthChannelConfig config = this.getAuthChannelConfig(dto);
        //判断能够鉴权的标识
        boolean flag = false;
        if (config != null){
            //是否存在该通道编码的调用service实现类(spring bean中存在通道编码的bean)
            boolean existBean = SpringUtil.getApplicationContext().containsBean(config.getChannelCode());
            if (existBean){
                flag = true;
            }
        }
        if (!flag){
            map.put("rspCode", "99");
            map.put("rspMsg", "找不到可用通道");
            log.info("企业信息要素验证,返回数据:"+map);
            this.saveBusinessAuthChannelOrder(dto, authResult, config);
            return map;
        }

        //调用鉴权通道
        BusinessAuthChannelService authChannelService =
                (BusinessAuthChannelService)SpringUtil.getBean(config.getChannelCode());
        authResult = authChannelService.auth(dto);

        //保存信息记录
        this.saveBusinessAuthChannelOrder(dto, authResult, config);
        Map<String, Object> resultMap = (Map<String, Object>)authResult.get("resultMap");
        log.info("企业信息要素验证,返回数据:"+resultMap);
        return resultMap;
    }

    /**
     *   鉴权要素参数校验
     * @param dto
     * @return boolean
     * @throws
     * @author Surpass
     * @date 2021/1/12 15:32
     */
    private boolean validateParameter(AuthChannelDto dto){
    }

    /**
     *   根据参数条件查询可用的鉴权通道
     * @param dto
     * @return com.p4.risk.entity.BusinessAuthChannelConfig
     * @throws
     * @author Surpass
     * @date 2021/1/12 15:32
     */
    private BusinessAuthChannelConfig getAuthChannelConfig(AuthChannelDto dto){
        //根据参数在配置表中查询第三方接口配置信息
    }

    /**
     *   保存操作记录
     * @param dto 企业信息鉴权信息
     * @param authResult 鉴权结果
     * @param config 企业鉴权通道配置
     * @return void
     * @throws
     * @author Surpass
     * @date 2021/1/12 15:33
     */
    private void saveBusinessAuthChannelOrder(AuthChannelDto dto, Map<String, Object> authResult,
                                              BusinessAuthChannelConfig config){
       
    }
}

解释一下:主要是 auth 这个方法时主要流程,根据参数查询出来的第三方接口配置字段的 channelCode ,使用SpringUtil在Spring中查找是否存在有该值的beanName,如果不存在,则直接保存操作记录后返回。如果存在则使用 SpringUtil.getBean(channelCode)获得该编码的bean,然后调用 authResult = authChannelService.auth(dto) 就进入到第三方校验实现类中进行校验,校验完毕后保存操作记录,流程结束。

尾言

代码不全,但注释应该足够了,如果对上述代码有疑问的烦请留言,如果各位喜欢这篇文章,劳烦各位伸出小手点个赞,收个藏,关个注。

上一篇下一篇

猜你喜欢

热点阅读