策略模式_扩展性_设计思路_拒绝大量if else
开始
在实际开发中可能会遇见这样的问题 ,做完的项目需要二次开发 现在在微信支付和支付宝的基础上添加一个银联支付
你哐哐哐开始写.测试...过几天又添加了几个,你渐渐发现,哐哐哐 好多重复代码,接口写一大堆. 有的比较聪明给一个type值
使用一个接口进行判断1:支付宝支付2:微信支付... 又发现好不美观
if (type == 1) { ... } else if (type == 2){ ... } else if (type == 3){ ... } else if (type == 4) { ... }
我们可以使用JAVA二十三中设计模式中的 策略模式
废话少说,少说废话.直接上代码一个简单的DEMO 自己扩展即可,玩法多样
一.我们先定义一个支付接口
1.1我们首先想一下我们这个抽象接口都需要什么
个人觉得就是需要一个 共性的方法和内容 这就是一个规范 在SpringBoot刚开始学习的时候我们都学过这样的一句话
约定大于配置 我们现在定义这个接口就是规范子类必须实现的
/** * @description: 工厂模式 + 策略模式 支付父接口 * @author: @Dog_E * @create: 2020-07-16 18:07 **/ public interface PayStrategy { /** * @Description: 预支付 * @Param: * @return: * @Author: @Dog_E * @Date: 2020/7/16 0016 */ void advanceAayment(JSONObject jsonParam); /** * @Description: 支付回调 * @Param: * @return: * @Author: @Dog_E * @Date: 2020/7/16 0016 */ void paySyntony(JSONObject jsonParam); /** * @Description: 支付类型 * @Param: [] * @return: int * @Author: @Dog_E * @Date: 2020/7/16 0016 */ int getType(); }
二.我们需要定义一个规格
2.1这个是规格是个什么玩意的呢,简单的说 还是 标识判断1:支付宝支付2:微信支付...
在这个里面我们现在就是使用枚举了 有人会说这样不是还是强耦合吗 只是我没有进行优化
打个比方来说 你可以把这个规格设计成库表对不对这多香了 你还可配置开关 比方说,我们现在前台有支付宝支付的入口 但是我们想停止使用
我们可在后台关闭支付宝支付对吧 但是要是写死那我们只能去修改代码再部署
/** * @description: 支付类型 * @author: @Dog_E * @create: 2020-07-16 18:17 **/ public enum PayType { /** * 支付宝支付 */ ALIPAY(1), /** * 微信支付 */ VX_PAY(2), /** * */ UNIONPAY(3); private int type; private PayType(int type) { this.type = type; } public int getType() { return this.type; } @Override public String toString() { return "PayType{" + "type='" + type + '\'' + '}'; } }
三.实现父接口
3.1其实思想就是 多态 继承 这解耦合并且解决重复代码的情况下我们还给各自的实现类中提供了自己的方法可以有自己的特性
同时有的小伙伴就会有一个疑惑,支付宝的参数和微信的参数完全都不一样,你在控制器层就只有一个接口你如何传递参数的?
我们可以通过JSON的方式传输参数,JSON体积小轻量化,方便快捷
3.2我先写一个对象用于接收参数
/** * @description: * @author: @Dog_E * @create: 2020-06-30 11:07 **/ public class TestA implements Serializable { private String sex; private String name; private String grade; private String age; @Override public String toString() { return "TestA{" + "sex='" + sex + '\'' + ", name='" + name + '\'' + ", grade='" + grade + '\'' + ", age='" + age + '\'' + '}'; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGrade() { return grade; } public void setGrade(String grade) { this.grade = grade; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public TestA() { } public TestA(String sex) { this.sex = sex; } public TestA(String sex, String name, String grade, String age) { this.sex = sex; this.name = name; this.grade = grade; this.age = age; } }
3.3实现类
/** * @description: 支付宝支付 * @author: @Dog_E * @create: 2020-07-17 09:11 **/ public class AliPayImpl implements PayStrategy { @Override public void advanceAayment(JSONObject jsonParam) { System.out.println("调用支付宝支付预支付"); } @Override public void paySyntony(JSONObject jsonParam) { System.out.println("调用支付宝支付回调"); } @Override public int getType() { return PayType.ALIPAY.getType(); } }
/** * @description: 微信支付 * @author: @Dog_E * @create: 2020-07-17 09:08 **/ public class VxPayImpl implements PayStrategy { @Override public void advanceAayment(JSONObject jsonParam) { JSONObject t = jsonParam.getObj("t"); boolean empty = ObjectUtils.isEmpty(t); if (!empty) { TestA testA = t.asBean(TestA.class); System.out.println("调用微信支付预支付 testA:" + testA.toString()); } else System.out.println("调用微信支付预支付" + " "); } @Override public void paySyntony(JSONObject jsonParam) { System.out.println("调用微信支付回调"); } @Override public int getType() { return PayType.VX_PAY.getType(); } }
/** * @program: ruoyi * @description: 银联支付 * @author: @Dog_E * @create: 2020-07-17 09:37 **/ public class UnionpayImpl implements PayStrategy { @Override public void advanceAayment(JSONObject jsonParam) { System.out.println("调用银联支预支付"); } @Override public void paySyntony(JSONObject jsonParam) { System.out.println("调用银联支付回调"); } @Override public int getType() { return PayType.UNIONPAY.getType(); } }
四.建设策略工厂
4.1这个就是相当于是核心内容了,你可以在这个地方进行增强,我这个地方只能提供思路
添加数据库呀从数据库查呀啥之类的你想做就做,不想做,各个实现的的代码都已经进行拆分了互不干扰
手动添加也一样
/** * @description: 支付工厂 * @author: @Dog_E * @create: 2020-07-17 10:22 **/ public class PayFactory { /** * @Param: Integer 规格 * @Param: PayStrategy 支付父接口 */ private Map<Integer, PayStrategy> map; public PayFactory() { /** List<PayStrategy> 支付父接口对象集合*/ List<PayStrategy> strategies = new ArrayList<>(); //TODO 这里写的就是各个实现类了 可以在这个地方做扩展 例如做数据库查询呀之类的判断使用for循环添加进去我就问你他不香吗? strategies.add(new AliPayImpl()); strategies.add(new UnionpayImpl()); strategies.add(new VxPayImpl()); //封装为一个Map对象 使用了java1.8的特性 /** * @Param: PayStrategy 支付父接口 * PayStrategy::getType 方法引用 这里就不讲解了 说白了就是调用了一下规格判断 拿规格当key 对象当做value */ map = strategies.stream().collect(Collectors.toMap(PayStrategy::getType, strategy -> strategy)); } public static class Holder { public static PayFactory instance = new PayFactory(); } // 获取了PayFactory支付工厂对象 public static PayFactory getInstance() { return Holder.instance; } public PayStrategy get(Integer type) { return map.get(type); } }
五.测试
/** * @program: ruoyi * @description: 测试 * @author: @Dog_E * @create: 2020-07-17 11:07 **/ @RestController public class TestController { @PostMapping("/test") public void test(@RequestBody JSONObject jsonParam) { //获取规格 Integer type = jsonParam.getInt("type"); //调用策略工厂 PayStrategy strategy = PayFactory.getInstance().get(type); if (strategy == null) { System.out.println("对应策略不存在"); } else { strategy.advanceAayment(jsonParam); strategy.paySyntony(jsonParam); } } }
5.1我这里测试使用的是Postman
5.2结果 更改JOSN type值即调用不同的方法 扩展性显而易见