dede网站地图模版,手机网站建设一般多少钱,厦门网红打卡景点有哪些,公司搭建网站基于多种设计模式重构代码
现状 系统目前支持三种业务流程#xff0c;业务A#xff0c; 业务B#xff0c;业务C#xff0c;每个流程有相同的业务逻辑#xff0c;也包含很多的特性化业务。由于之前业务流程的开发是快速迭代的#xff0c;而且迭代了很多次#xff0c;开发…基于多种设计模式重构代码
现状 系统目前支持三种业务流程业务A 业务B业务C每个流程有相同的业务逻辑也包含很多的特性化业务。由于之前业务流程的开发是快速迭代的而且迭代了很多次开发同学们应该可以理解过程中免不了面向过程、CV大法…现在无论是业务发展还是我们产研团队对于业务的理解都趋于稳定是时候该还债了重构代码我辈义不容辞恰好新需求来了需要在原有业务B流程中增加一个业务环节申请支付业务发起时扣减对应客户的资产余额。
业务流程A抽象后伪码如下
public void applyPay(Request request) {//数据查询query();//数据校验doCheck(request);//业务逻辑处理if (request.getFlag()) {//资产校验//扣减资产//生成审批流数据//推送钉钉processA();} else {//资产校验//扣减资产//生成审批流数据//推送钉钉processB();}//数据更新update();}更巧的是之前业务A中做过类似的业务而且需求评估的时候产品信誓旦旦的说业务B、C中肯定不会有这个业务。
可以预见的是业务C中将来也会有这个业务。
Don not Repeat yourself这个逻辑公共化处理是必要的。 模板模式
对于上述业务流程很容易想到模板模式对代码进行通用性抽象优化 定义算法步骤骨架并允许子类对一个或多个步骤进行实现 定义模板流程定义抽象方法子类强制实现如有必要定义钩子方法
模板模式很容易理解。
定义一个接口类
public interface IApplyPayProcessor {void applyPay(ApplyPayRequest request);
}定义抽象父类
public abstract class AbstractApplyPayProcessorT implements IApplyPayProcessor{/*** 申请支付模板方法* param request*/Overridepublic void applyPay(ApplyPayRequest request) {//数据查询T t query(request);//校验check(t);//业务逻辑处理process(t, request);//数据保存save(t);//通用业务逻辑处理sendMsg(t);}private void sendMsg(T t) {//发送业务逻辑完成通知 event、msg......实际代码省略}/*** 根据业务,子类实现* param request* return*/public abstract T query(ApplyPayRequest request);/*** 根据业务,子类实现* param t* return*/public abstract Boolean check(T t);/*** 根据业务,子类实现* param t* param request*/public abstract void process(T t, ApplyPayRequest request);/*** 根据业务,子类实现* param t*/public abstract void save(T t);
}
子类实现
对于业务A继承AbstractApplyPayProcessor并根据自身业务的逻辑实现相应的方法。
对于业务B、业务C也是类似的代码只需要实现相应的方法无需对业务流程进行重新的编排毕竟父类已经定义了骨架方法。
public class BizAApplyPayProcessor extends AbstractApplyPayProcessorBizADO{Overridepublic BizADO query(ApplyPayRequest request) {return new BizADO();}Overridepublic Boolean check(BizADO o) {//..子类业务逻辑省略return Boolean.TRUE;}Overridepublic void process(BizADO o, ApplyPayRequest request) {//..子类业务逻辑省略}Overridepublic void save(BizADO o) {//..子类业务逻辑省略}
}工厂模式
经过第一步模板模式优化后我们该怎么使用呢
通常我们会在service层这样使用
public void doApplyPay(ApplyPayRequest request) {....其他业务逻辑if (request.getType().equals(A)) {BizAApplyPayProcessor processor new BizAApplyPayProcessor();processor.applyPay(request);} else if (request.getType().equals(B)) {BizBApplyPayProcessor processor new BizBApplyPayProcessor();processor.applyPay(request);} else if (request.getType().equals(C)) {BizCApplyPayProcessor processor new BizCApplyPayProcessor();processor.applyPay(request);}..... 其他业务逻辑}我们很大概率会按照上述代码的编写方式先通过if/else判断然后使用new这个关键字实例化对应的实体或者Spring的方式注入对应的方式。
new代表着实例化意味着我们的代码需要依赖具体的实现而通常推荐的编程是面向接口而不是面向实现。
当有新的类型比如业务D被添加进来时这个service需要修改if/else逻辑需要改变不符合开闭原则设计模式的核心的一点就是封装可变的部分。
可以使用工厂模式将if/else封装在单独的类伪代码如下
public class BizFactory {public static IApplyPayProcessor getApplyPayProcessor(String bizType) {IApplyPayProcessor processor;if (A) {processor new BizAApplyPayProcessor();processor.applyPay(request);} else if (B) {processor new BizBApplyPayProcessor();processor.applyPay(request);} else if (C) {processor new BizCApplyPayProcessor();processor.applyPay(request);}return processor;}
}//service层使用工厂类直接获取对应的实例
public class ClientService {public void doApplyPay(ApplyPayRequest request) {BizFactory.getApplyPayProcessor(request.getType());}
}这样做起来看起来只是将代码从service层移动到了一个BizFactory中问题依然是存在的有什么好处呢
service层不再随着实现的变化而变化尽量往单一职责去靠拢注意我这里说的是尽量因为往往我们会做一个取舍。BizFactory可以有很多业务工厂其他业务service以后也不需要变化只需要变化BizFactory
策略模式
我们可以看到对于工厂本身而言虽然我们将对象的使用和创建已经分离开来使用工厂模式来专注于对象的创建当新增业务类型时比如业务D时我们需要修改工厂模式不符合开闭原则。
如何进行进一步优化呢让工厂模式不随着业务类型的增加而进行修改呢。
答案即是使用策略模式 定义一系列的算法或策略并将每个算法封装在单独的类中使得它们可以互相替换。通过使用策略模式可以在运行时根据需要选择不同的算法而不需要修改客户端代码。 step1 先定一个枚举BizTypeEnum 用来标识业务类型也就是策略的集合。
Getter
public enum BizTypeEnum {A(1, 业务A),B(2, 业务B),C(3, 业务C),D(4, 业务D),;private int code;private String msg;BizTypeEnum(int code, String msg) {this.code code;this.msg msg;}/*** 整形值转换为枚举类** param value 值* return 枚举类*/public static BizTypeEnum valueOf(int value) {for (BizTypeEnum anEnum : values()) {if (value anEnum.getCode()) {return anEnum;}}return null;}
}step2 定义一个注解ApplyPay用来标记策略类
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
public interface ApplyPay {BizTypeEnum bizType() default BizTypeEnum.A;
}step3 使用注解ApplyPay改造标记策略类
ApplyPay(bizType BizTypeEnum.A)
public class BizAApplyPayProcessor extends AbstractApplyPayProcessorBizADO{Overridepublic BizADO query(ApplyPayRequest request) {return new BizADO();}Overridepublic Boolean check(BizADO o) {//..子类业务逻辑省略return Boolean.TRUE;}Overridepublic void process(BizADO o, ApplyPayRequest request) {//..子类业务逻辑省略}Overridepublic void save(BizADO o) {//..子类业务逻辑省略}
}ApplyPay(bizType BizTypeEnum.B)
public class BizBApplyPayProcessor extends AbstractApplyPayProcessorBiZBDO{Overridepublic BiZBDO query(ApplyPayRequest request) {return null;}Overridepublic Boolean check(BiZBDO biZBDO) {return null;}Overridepublic void process(BiZBDO biZBDO, ApplyPayRequest request) {}Overridepublic void save(BiZBDO biZBDO) {}
}step4 识别加载封装策略类改造工厂类 可以借助Spring的拓展能力识别策略类的注解并将策略实例化后使用集合保存当然如果没有使用Spring框架也可以借助反射等来进行此动作。 public class BizFactory implements ApplicationListenerContextRefreshedEvent {private static MapBizTypeEnum, IApplyPayProcessor APPLY_PAY_MAP new ConcurrentHashMap(8);public static IApplyPayProcessor getApplyPayProcessor(BizTypeEnum bizType) {return APPLY_PAY_MAP.get(bizType);}Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {ApplicationContext applicationContext event.getApplicationContext();//申请支付工厂初始化MapString, Object beansWithAnno applicationContext.getBeansWithAnnotation(ApplyPay.class);if (beansWithAnno ! null) {beansWithAnno.forEach((key, value) - {BizTypeEnum bizType value.getClass().getAnnotation(ApplyPay.class).bizType();APPLY_PAY_MAP.put(bizType, (IApplyPayProcessor) value);});}}
}使用策略模式改造完之后显而易见的改造后不同的业务被封装在不同的类中工厂模式也无需知晓每个类只需要根据业务类型加载即可。
每次新增业务类型时只需要新增策略类即可无需对service和factory进行修改。