java 策略模式的表设计与代码实现, 彻底解决 if 分支, 实现企业级功能启用禁用

一、描叙

1、为什么要使用策略模式?

  • 在某些业务场景下,我想添加 qq登录,微信登录,阿里账号登录,网易账号第三方登录,但是在某一天可能因为一些原因,我们不需要其中一个第三方登录了,患者第三方不在提供支持,比如网易公司不再提供登录了, 那我们需要修改代码,移除网易账号登录功能,但是某天网易公司账号有可以使用了, 我们又需要修改代码来实现这一功能

  • 如果我们使用了策略模式, 我们在后台会有一个管理列表,可以直接禁用/ 启用某一个功能
    在这里插入图片描述

  • 通过策略Id (前端传递) 找到对应的容器bend,调用对应的实现方法即可

  • 如果哪天第三方不在支持或不想要了,直接禁用即可, 如果哪天又想要了,直接启动即可, 如果想在添加新的策略,也无需改变原有的所有代码,大大降低了耦合,避免业务改动带来的一系列隐藏问题

二、代码实现

当前项目使用 springboot 2.0.1 + mybatis3.1

1、sql 脚本, 策略表

CREATE TABLE `t_admin_strategy` (
  `id` varchar(32) NOT NULL COMMENT 'ID',
  `strategy_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '策略名',
  `strategy_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '策略id',
  `strategy_type` int(2) NOT NULL COMMENT '策略type(字典code)',
  `strategy_bean_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '策略执行 spring容器的beanid',
  `disable` int(1) NOT NULL DEFAULT '0' COMMENT '是否禁用(字典code 0-否 1-是)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='策略';

2、目录结构

添加了 发送消息的策略 和支付策略

在这里插入图片描述

2、SpringUtils 工具类

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

}

3、AdminStrategy 策略类

/**
 * 策略表
 */
@Data
@TableName("t_admin_strategy")
public class AdminStrategy {
    /**
     * 策略Id
     */
    private String id;
    /**
     * 策略名
     */
    private String strategyName;
    /**
     * 策略Id
     */
    private String strategyId;
    /**
     * 策略类型(如: 1-短信 2-支付 3-登录)
     */
    private Integer strategyType;
    /**
     * spring容器 beanId ,用于找到对应的策略方法
     */
    private String strategyBeanId;
    /**
     * 是否禁用
     */
    private Integer disable = 0;
}

3、AdminStrategyMapper

public interface AdminStrategyMapper  extends BaseMapper<AdminStrategy> {
}

4、StrategyContext 策略Id 获取bend类

/**
 * 策略
 */
@Component
public class StrategyContext {

    @Autowired
    private AdminStrategyMapper strategyMapper;

    /**
     * 通过策略Id 寻找容器Id
     * @param strategyId
     * @param strategyType
     * @param t
     * @param <T>
     * @return
     */
    public <T> T getStrategy(String strategyId, Integer strategyType, Class<T> t) {
        // strategyId bean id 验证参数
        if (StringUtils.isEmpty(strategyId)) {
            return null;
        }
        if (strategyType == null) {
            return null;
        }
        if (t == null) {
            return null;
        }
        // 根据策略id查询 (策略id不能重复)
        AdminStrategy strategy = strategyMapper.selectOne(new LambdaQueryWrapper<AdminStrategy>()
                .eq(AdminStrategy::getStrategyId, strategyId)
                .eq(AdminStrategy::getStrategyType, strategyType)
                .eq(AdminStrategy::getDisable, 0)
        );
        if (strategy == null) {
            return null;
        }
        String strategyBeanId = strategy.getStrategyBeanId();
        if (StringUtils.isEmpty(strategyBeanId)) {
            return null;
        }
        T bean = SpringUtils.getBean(strategyBeanId, t);
        return bean;
    }
}

5、支付策略

接口

/**
 * 支付策略
 */
public interface PayStrategy {

    String toHtml();
}

实现1

/**
 * 策略if 阿里支付
 */
@Component
public class AliPayStrategy implements PayStrategy {
    @Override
    public String toHtml() {
        return "对接阿里";
    }
}

实现2

/**
 * 策略if 银联支付
 */
@Component
public class UnionPayStrategy implements PayStrategy {
    @Override
    public String toHtml() {
        return "对接银联";
    }
}

6、消息发送策略

接口

/**
 * 消息策略
 */
public interface MsgStrategy {
    /**
     * 共同行为方法
     *
     * @return
     */
    String sendMsg(String phone);
}

实现1

/**
 * 策略if 阿里云发送短信
 */
@Component
public class AliYunStrategy implements MsgStrategy {
    @Override
    public String sendMsg(String phone) {
        return "使用阿里云发送短信";
    }
}

实现2

/**
 * 策略if 华为发送短信
 */
@Component
public class HuaWeiStrategy implements MsgStrategy {
    @Override
    public String sendMsg(String phone) {
        return "使用华为发送短信";
    }
}

7、测试接口类

@RestController
public class TestController{
    @Autowired
    private StrategyContext strategyContext;

    @GetMapping("/sendMsg")
    public String sendMsg(String strategyId, String phone) {
        // type = 短信
        MsgStrategy msgStrategy = strategyContext.getStrategy(strategyId, 1, MsgStrategy.class);
        if (msgStrategy == null) {
            return "当前渠道已经关闭或者是不存在";
        }
        return msgStrategy.sendMsg(phone);
    }


    @GetMapping("/toPayHtml")
    public String toPayHtml(String strategyId) {
        // type = 支付
        PayStrategy payStrategy = strategyContext.getStrategy(strategyId, 2, PayStrategy.class);
        if (payStrategy == null) {
            return "当前渠道已经关闭或者是不存在";
        }
        return payStrategy.toHtml();
    }
}

三、测试

策略表数据,
在这里插入图片描述

1、发送短信策略测试

传递不同的策略Id 根据策略自动调用不同的实现
在这里插入图片描述

在这里插入图片描述

2、支付策略测试

传递不同的策略Id 根据策略自动调用不同的实现
在这里插入图片描述
在这里插入图片描述

3、关闭渠道测试

禁用阿里云短信功能
在这里插入图片描述
已经关闭了
在这里插入图片描述

  • 以上部分内容来自于蚂蚁课堂 http://www.mayikt.com/

  • 个人开源项目(通用后台管理系统)–> https://gitee.com/wslxm/spring-boot-plus2 , 喜欢的可以看看

  • 本文到此结束,如果觉得有用,动动小手点赞或关注一下呗,将不定时持续更新更多的内容…,感谢大家的观看!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兮家小二

妳的鼓励是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值