记一次多重if判断优化

有时候写代码,你会发现越写越有劲,觉得越有趣,时间在不知不觉中流逝

先看一下需求场景

现在开始发挥你们的思路,如果要你们对接,你们会怎么做,写在一个方法里然后判断msgType的类型,然后做相应的事情? 那可就完了,这么多个类型你要挨个判断不说,业务逻辑都写在了一个方法里,你不觉得这样耦合太紧了吗?你当然可以在订阅主题的方法里只写判断然后调用相应的方法,但是这么做。。总有点不好吧,如果你觉得没事,那就没事,当然你可能还会说把多个方法订阅这一个主题,但是注意。在kafka中同一用户组不能订阅同一主题中的同一分区,那你会说弄多个分区不就好了么?恩。。这样问题更大,建议去系统的学习下kafka,那你会觉得那我每个方法订阅的不在同一用户组不就行了?是可以,但是你不觉得弄这么多方法订阅同一主题很别扭?假如主题名称改了,那你得改32个(当然主题名不可能随意更改)总之这样不利于维护,而且看起来很别扭

在此之前我看过一些关于if优化的博客,大概也就是用策略模式加工厂模式代替

当我看到我对接的kafka的消息中是通过msgType来判断的时候我就想到了,但是。。这么做弊端更大。看过的应该知道,对于每个情况都得创建一个类来实现一个特定的接口,,,那么我这里有32种情况,就得创建32个类。。这不疯了么

当然聪明的我肯定不会这么干,那我会怎么做的呢?
其实和上面那个策略模式类似或者说就是,只是我把“类”改成了“方法”
你定义32个类来做,肯定疯了,但是32个方法不会呀。。所以我先写枚举,把每种情况都一一列出来

在这里插入图片描述

这里对应的就是那32种情况

然后定义一个注解

在这里插入图片描述

这个注解实际上是用来标注,即我们扫描的时候方便一点,不然你怎么扫描,你怎么知道哪个类中的哪个方法是我们需要调用的。

当然还有一个注解,是放在方法上的

在这里插入图片描述

里面有个值,就是我们刚刚定义的那个枚举类型,

整体思路是这样,通过扫描有DeliveryKafkaConsumer该注解的类,然后再扫描有该类中有DeliveryKafkaConsumerMethod注解的方法,然后拿到DeliveryKafkaConsumerMethod注解的值,就知道当前这个方法是对应的哪种情况

先来看下怎么使用

创建一个类加上DeliveryKafkaConsumer注解

在这里插入图片描述

然后定义一个方法加上DeliveryKafkaConsumerMethod注解并指定枚举类型说明你要干什么
在这里插入图片描述

那么问题来了,我该怎么去调用这个方法,

其实很简单具体实现

@Component
@Getter
public class DeliveryEventConsumerParsing implements ApplicationContextAware {

    private final Map<String, Map<Object, Method>> map = Maps.newConcurrentMap();

    private static final ImmutableMap.Builder<String, String> BUILDER = new ImmutableMap.Builder<>();

    public static final ImmutableMap<String, String> INFO_MAP;

    static {
        MessageDeliveryEventConsumerEnum[] values = MessageDeliveryEventConsumerEnum.values();
        for (MessageDeliveryEventConsumerEnum message : values) {
            BUILDER.put(message.getId(), message.getName());
        }
        INFO_MAP = BUILDER.build();
    }

    private ApplicationContext applicationContext;

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

    private void parsing() {
        Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(DeliveryKafkaConsumer.class);
        Set<Map.Entry<String, Object>> entries = beanMap.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            Object obj = entry.getValue();
            scannerConsumerMethod(obj);
        }
    }

    private void scannerConsumerMethod(Object obj) {
        Class<?> clazz = obj.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            addConsumerMethod(obj, method);
        }

    }

    private void addConsumerMethod(Object obj, Method method) {
        method.setAccessible(true);
        if (method.isAnnotationPresent(DeliveryKafkaConsumerMethod.class)) {
            DeliveryKafkaConsumerMethod kafka = method.getAnnotation(DeliveryKafkaConsumerMethod.class);
            Map<Object, Method> objMap = Maps.newHashMap();
            objMap.put(obj, method);
            map.put(kafka.value().getId(), objMap);
        }
    }
}

具体调用的方法,这个方法要订阅这个主题,记得要把DeliveryEventConsumerParsing这个类注入进来,因为我们的具体要调用的方法保存在这个类
在这里插入图片描述

这个订阅主题的方法,你们可以根据自己的需求的实现,我这里的匹配了一下方法的参数,如果目标方法的参数 我有或者我能从spring中拿到,那我就给他注入进去

在这里插入图片描述

自己灵活实现吧,

注意:这里还有个注意的点 如果你当前类加了 @DeliveryKafkaConsumer这个注解和类中的方法刚好也加了 @DeliveryKafkaConsumerMethod这个注解,那么这时候该类就不能被动态代理,比如定时任务之类的 因为在spring boot中默认使用cglib的动态代理方式,cglib是通过继承重写方法实现的,如果你这个类被代理了,那么他就会重写你的方法,但是导致的问题就是你这个方法上的注解就丢了,扫描不到了

如果你想在同一个类即使用@DeliveryKafkaConsumer和@DeliveryKafkaConsumerMethod注解,又想被动态代理,这里以定时任务为例

在这里插入图片描述
我这里是更新老师的信息,但是有个问题,先要去查询别的接口,并且这个接口要Token才能访问,如果我每次调用这个方法的时候都去重新获取Token 的话,显然是不合理的,
我看了一下,接口返回的Token有效期为12个小时,那就好办了,我维护一个定时任务,定时来更新Token

在这里插入图片描述

在这里插入图片描述

之前说过,不能写在同一类,但是我有想在一个类中维护,所以定义一个内部类就好了

其实我之前尝试过很多解决方案,都可以解决,但是我还是觉得不太好,所以最后才想到这个内部类的写法

这样的话就很方便我们写我们自己的业务逻辑了

如果我们想监听新增老师的 方法
只需和下面一样就行

在这里插入图片描述

这样写的主要目的就是把业务逻辑分开,有利于自己维护

如有不对,欢迎指正

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值