前言
平常的开发工作中同一个业务不同的场景一般是采用不同的处理方式,如何根据不同的场景进行不同的业务实现,if else一定是处理此类问题的万能钥匙,不管多少分支,if绝对管够。这种处理方式确实万能,但是这么肆无忌惮的怼上这么多if总感觉不太优雅,下面就结合实际的业务场景说下如何优化此类问题。
现在有一个营销活动支付场景,各种营销活动都是在支付成功的回调中进行对应的业务处理,现在需要实现的是分销活动、拼团活动,后期还会增加其他的活动类型,不同的活动处理逻辑不同。支付成功回调中最初的实现伪代码如下:
if(活动id=11){ // 执行分销活动的业务处理逻辑 } if(活动id=12){ // 执行拼团活动的业务处理逻辑 } // 其他营销活动....
下面就结合实际场景进行优化。
代码优化
优化1:工厂模式+策略模式代替万能if
活动类型与活动处理类做映射关系处理,根据活动类型获取活动处理类,然后执行对应活动业务处理。将活动类型与活动处理类组成key-value形式封装成map组合,每次根据活动类型获取对应的活动类型处理类。
先说策略模式,官方介绍不说了,通俗易懂的说下自己的理解:对于多种活动实现而言,需要有一个公共的业务实现方法,每种活动的具体处理逻辑由子类或是实现类进行处理。公共的业务实现方法一般在父类或是抽象类中,具体的业务由子类或是实现类处理。对应代码说下上面的两种关系:
活动处理顶级父类,提供活动处理的公共逻辑:
public abstract class AbstractActivity { // 活动处理逻辑,具体业务逻辑由子类实现 public abstract void handleActivity(); }
分销活动处理类,执行分销活动的具体逻辑:
public class DistributionActivity extends AbstractActivity { @Override public void handleActivity() { System.out.println("分销活动实现逻辑"); } }
拼团活动处理类,执行拼团活动的具体逻辑:
public class PinTuanActivity extends AbstractActivity { @Override public void handleActivity() { System.out.println("拼团活动实现逻辑"); } }
想要根据不同的活动类型获取不同的活动处理类,而每次获取的时候不想重复创建对象,可以使用工厂模式实现。
为便于管理,将活动类型组装成枚举形式:
public enum ActivityEnum { DISTRIBUTION(11,"分销活动"), PIN_TUAN(12,"分销活动"); // 活动类型 private Integer activityType; // 活动类型描述 private String desc; /** * @Author: txm * @MethodMame: getActivityEnum * @Param: [activityType] * @Return: com.kawa.h5.api.pay.notify.ActivityEnum * @Description: 根据活动类型获取活动枚举 * @Date: 2022\10\26 0026 0:22 **/ public static ActivityEnum getActivityEnum(Integer activityType){ for (ActivityEnum activityEnum : ActivityEnum.values()) { if(activityType == activityEnum.getActivityType()){ return activityEnum; } } return null; } ActivityEnum(Integer activityType, String desc) { this.activityType = activityType; this.desc = desc; } public Integer getActivityType() { return activityType; } public void setActivityType(Integer activityType) { this.activityType = activityType; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
活动工厂:
public class ActivityFactory { // 活动工厂 private static ActivityFactory activityFactory=new ActivityFactory(); // 活动集合,key为活动枚举信息,value为活动实现类 private static Map<ActivityEnum,AbstractActivity> activityMap=new HashMap<ActivityEnum,AbstractActivity>(); // 初始化活动对象 static{ activityMap.put(ActivityEnum.DISTRIBUTION,new DistributionActivity()); activityMap.put(ActivityEnum.PIN_TUAN,new DistributionActivity()); /** * @Author: txm * @MethodMame: getInstance * @Param: [] * @Return: com.kawa.h5.api.pay.notify.ActivityFactory * @Description: 获取工厂实例 * @Date: 2022\10\25 0025 23:41 **/ public static ActivityFactory getInstance(){ return activityFactory; } /** * @Author: txm * @MethodMame: getActivity * @Param: [activityEnum] * @Return: void * @Description: 获取活动子类 * @Date: 2022\10\26 0026 0:13 **/ public AbstractActivity getActivity(ActivityEnum activityEnum){ // 获取抽象活动的实现类对应的枚举以及活动实现类 AbstractActivity abstractActivity = activityMap.get(activityEnum); return abstractActivity; }
优化后根据活动类型执行活动处理逻辑:
// 利用活动工厂根据活动类型获取分销活动业务处理类 AbstractActivity abstractActivity = ActivityFactory.getInstance().getActivity(ActivityEnum.getActivityEnum(11)); // 执行活动处理逻辑 abstractActivity.handleActivity(); // 输出:分销活动实现逻辑
上面就是使用工厂模式+策略模式代替if else,只需要传递具体的活动类型即可,是不是比最初的实现方式更加简介。当然这种实现也有问题:上面的工厂类中进行活动处理类初始化时使用new对象的方式,思考是否可以利用spring核心之一的IOC方式代替new的方式创建对象,答案是可以的,看优化2.
优化2:spring容器启动完成业务对象的初始化
容器启动过程中,将各种活动处理类加载到容器中,并与活动类型建立映射关系。可以使用注解进行关联,并根据注解获取对应的活动业务实现类。容器加载过程中完成`activityMap`的组装。涉及的spring知识点:
// 根据注解类型获取带有注解的bean信息 Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(注解.class);
spring容器初始化操作方式之一:ApplicationListener中onApplicationEvent方法。
自定义活动注解,添加到活动处理类上完成关系绑定映射。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface ActivityAnnotation { ActivityEnum value(); }
分销活动处理类,添加自定义注解以及@Componet交由容器管理
@Component @ActivityAnnotation(ActivityEnum.DISTRIBUTION) public class DistributionActivity extends AbstractActivity { /** * @Author: txm * @MethodMame: handleActivity * @Param: [] * @Return: void * @Description: 分销活动实现逻辑 * @Date: 2022\10\25 0025 23:57 **/ @Override public void handleActivity() { System.out.println("分销活动实现逻辑"); } }
拼团活动处理类添加自定义注解以及@Componet交由容器管理
@Component @ActivityAnnotation(ActivityEnum.PIN_TUAN) public class PinTuanActivity extends AbstractActivity { /** * @Author: txm * @MethodMame: handleActivity * @Param: [] * @Return: void * @Description: 拼团活动实现逻辑 * @Date: 2022\10\25 0025 23:59 **/ @Override public void handleActivity() { System.out.println("拼团活动实现逻辑"); } }
活动工厂中添加组装activityMap的逻辑
public class ActivityFactory { // 活动工厂 private static ActivityFactory activityFactory=new ActivityFactory(); // 活动集合,key为活动枚举信息,value为活动实现类 private static Map<ActivityEnum,AbstractActivity> activityMap=new HashMap<ActivityEnum,AbstractActivity>(); /** * @Author: txm * @MethodMame: getInstance * @Param: [] * @Return: com.kawa.h5.api.pay.notify.ActivityFactory * @Description: 获取工厂实例 * @Date: 2022\10\25 0025 23:41 **/ public static ActivityFactory getInstance(){ return activityFactory; } /** * @Author: txm * @MethodMame: addActivityMap * @Param: [] * @Return: void * @Description: 活动集合中添加活动信息 * @Date: 2022\10\25 0025 23:53 **/ public void buildActivityMap(ApplicationContext applicationContext){ // 获取抽象活动的实现类对应的枚举以及活动实现类,即获取带有ActivityAnnotation注解的对象信息 Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(ActivityAnnotation.class); for (Map.Entry<String, Object> stringObjectEntry : beansWithAnnotation.entrySet()) { Class<?> targetClass = AopProxyUtils.ultimateTargetClass(stringObjectEntry.getValue()); ActivityAnnotation activityAnnotation = targetClass.getAnnotation(ActivityAnnotation.class); activityMap.put(activityAnnotation.value(),applicationContext.getBean(stringObjectEntry.getKey(),AbstractActivity.class)); } } /** * @Author: txm * @MethodMame: getActivity * @Param: [activityEnum] * @Return: void * @Description: 获取活动子类 * @Date: 2022\10\26 0026 0:13 **/ public AbstractActivity getActivity(ActivityEnum activityEnum){ // 获取抽象活动的实现类对应的枚举以及活动实现类 AbstractActivity abstractActivity = activityMap.get(activityEnum); return abstractActivity; } }
自定义监听器用于容器加载完成初始化activityMap
@Component public class PersonalContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); ActivityFactory.getInstance().buildActivityMap(applicationContext); } }
测试:根据活动类型执行对应的业务处理
// 利用活动工厂根据活动类型获取分销活动业务处理类 AbstractActivity abstractActivity = ActivityFactory.getInstance().getActivity(ActivityEnum.getActivityEnum(11)); // 执行活动处理逻辑 abstractActivity.handleActivity(); // 输出:分销活动实现逻辑
以上是关于if else代码优化的实战记录,如果感觉有收获欢迎点赞,如果有更好的方式欢迎评论区留言!