基于模版方法模式优化if、else的思路

平常在公司看到很多业务逻辑的代码可能就是if/else各种判断,虽然也有一些设计模式能够解决一些问题,但是感觉都不是特别好用。刚好这次有个场景比较符合这个命题来聊一下如何去实践的.

  1. 触发场景

目前有些场景需要基于BinLog的变化去做一些业务变更操作,比如有

  1. 一些表字段中冗余了各种名称,希望这些源表发生变更的时候,能够顺带更新冗余字段表中的值。
  2. 随着一些表的数据越来越大,一些表关联让SQL越来越慢,目前是希望压缩数据,所以数据发生变化了需要实时通知某些业务。
  3. 还有一些最终一致性的业务

基于阿里云DTS封装成Spring的应用

目前已经将Binlog发送到消息队列存储好了,表名为Tag,开发根据自己关注的表名指定好,然后去处理特定的逻辑

消费者:
伪代码 :

public class BinlogConsumer{
	public void consumer(TableInfo table){
    	String tableName = table.getTableName();
		if(request.equals("TB_A")){
			// 处理A表变更后的业务逻辑
		}else if(request.equals("TB_B")){
			// 处理B表变更后的逻辑
		}else if(request.equals("TB_C")){
			// 处理C表变更后的逻辑
		}else if(request.equals("TB_D")){
			// 处理D表变更后的逻辑
		}
	}
}

随着业务要处理的表越来越多,会发现判断也会越来越多。
如果每个变更业务逻辑的方法抽象成小的方法还好,最怕的就是有的开发拿着就是一把梭,所有逻辑全部怼到一个方法!!!
我已经遇到过太多了!太辛苦了。
目前对于这种场景的话一开始制定好规范,让其他开发按照同样的套路去做的话会省力一点。
通过JDK8的Function编程去实现:
2. 实现思路
2.1 基于方法拆分

import org.springframework.util.Assert;
import java.util.function.Consumer;
/**
 * @Module 执行器
 * @Description 等值比较处理
 * @Author liukaixiong
 * @Date 2020/12/11 15:48
 */
public interface EqualsValueInvoke<T> {
    /**
     * 等值比较执行方法
     *
     * @param eqA      值A
     * @param eqB      值B
     * @param req      请求参数
     * @param consumer 具体的执行方法
     * @return
     */
    default void invoke(String eqA, String eqB, T req, Consumer<T> consumer) {

        Assert.notNull(eqA, "eqA is not null");
        Assert.notNull(eqB, "eqB is not null");

        if (eqA.equals(eqB)) {
            consumer.accept(req);
        }
    }
}

使用的测试用例:

public class EqualsValueInvokeTest extends TestCase implements EqualsValueInvoke<String> {
     @Test
    public void testInvoke() {
        String request = "Table_B";
		// 在这个方法内可以根据特定的表找对应的处理方法
        invoke(request, "Table_A", request, this::processTableA);
        invoke(request, "Table_B", request, this::processTableB);
    }

    public void processTableA(String req) {
        String s = "processTableA_" + req;
        System.out.println(s);
    }

    public void processTableB(String req) {
        String s = "processTableA_" + req;
        System.out.println(s);
    }
}

看上去会稍微清晰一点,当然实际上还是if、else的写法。

2.2 基于注解加反射

在方法1的基础上在升级一下,利用注解来标明关注的TableName,Map来存储关系

import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 等值比较
 * @Module 处理器
 * @Description 等值处理器
 * @Author liukaixiong
 * @Date 2020/12/11 14:38
 */
public interface EqualsValueProcess<T> extends InitializingBean {

    Map<String, Method> equalsMap = new HashMap<String, Method>();
	
    // 初始化数据关系
    @Override
    default void afterPropertiesSet() throws Exception {
        Method[] methods = this.getClass().getMethods();
        Arrays.stream(methods).filter((t) -> {
            return t.getAnnotation(RequestMapping.class) != null;
        }).forEach((method) -> {
            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
            String value = requestMapping.value()[0];
            equalsMap.put(value, method);
        });
    }

    default void process(Object obj, String key, T request) throws Exception {
        Method method = equalsMap.get(key);
        if (method != null) {
            method.invoke(obj, request);
        } else {
            System.out.println("找不到匹配的值:" + key);
        }
    }
}

流程思路:
● 初始化该类的时候,
○ 遍历该类的所有方法
○ 遍历每个方法的同时,查找方法上面的注解
○ 关联注解的值和方法,存储关系
● 调用的时候,根据传递进来的值去map中根据key找对应的值
● 然后执行

测试用例:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Module TODO
 * @Description TODO
 * @Author liukaixiong
 * @Date 2020/12/11 15:19
 */
@RunWith(JUnit4.class)
public class EqualsValueProcessTest implements EqualsValueProcess<String> {
	// 假设这是Binlog传递过来的参数
    private String defaultTable = "Table_A";

    @Before
    public void init() throws Exception {
        afterPropertiesSet();
    }

    @Test
    public void testProcess() throws Exception {
        process(this, defaultTable, "你好");
    }
    
    // 这就是map中的key,方法名称就是值
    @RequestMapping(value = "Table_A")
    public void methodA(String param) {
        System.out.println(param + "\t A");
    }

    @RequestMapping(value = "Table_B")
    public void methodC(String param) {
        System.out.println(param + "\t B");
    }
}

当然这里只是做测试(用的是SpringMVC的@RequestMapping),可以根据许多场景去制定注解的规则,不一定非得是等值比较。

这样的实现的话,就会将对应的值根据注解路由到特定的方法。

可能是使用起来比较习惯的方式。

第一种方式的话,读起来感觉会更清晰一点,所有表名旁边就是对应的处理逻辑方法,性能比第二种要好。

第二种方式的话:使用起来会更方便,直接告诉注解你需要那张表的数据,用惯了Spring的会更贴切。

其实根据这些思路还可以衍生其他方法,定义好规范的话,统一管理对大家都好。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值