什么?代码里全是if-else

前言


『代码中if-else是否已经让你不厌其烦? 』

『磨刀霍霍向它的想法是否预谋已久?』
『却苦于没有好的方式?』
  来来来,xdm,我就在此献丑,抛转引玉,把自己的解决方式贴出来供大伙儿参考参考。

对于下面这样的代码,大伙肯定都不陌生,当然啦,像这种比较少的if-else,我的理解是一般前期也没有必要去优化,除非说你前期很明确后面有很多类型或者说逻辑需要处理,那在前期能很优雅地解决if-else就很有必要了
很多时候,项目刚起步,一是业务本身的不明确,二是一般前期项目需求排期都比较近,尽可能高效地完成开发工作比较重要,虽然不至于所有代码都是一把梭,但是后面回头看来,看到自己写的代码,也会忍不住喷一句狗屎在这里插入图片描述
,业务成熟,项目成型后,50%以上的代码都是可优化的(也可能是本人水平过于低下☹)。

在这里插入图片描述
无论是前期业务逻辑设计复杂导致的if-else,还是后期屎山代码堆砌的if-else,在我看来,其实就是一种策略思想的应用场景,当然啦,策略模式的话,不知道大伙儿用的多不多,用来解决上述场景再合适不过了。



策略模式


公共接口

首先针对于上图if-else的场景,先定义一个接口,通用的支付接口类

public interface IPay {
    void pay();
} 

再定义一个注解,用来对每一种的策略进行标记

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PayCode {
    String value();
    String name();
}
具体实现类

接下来就是具体的实现类
实现类就是具体的策略,当我们需要新增一个策略时,例如美团支付等,直接新增一个实现类即可,不但符合我们常说的开闭原则,还实现了对业务逻辑的解耦,大伙别看下面代码简单,毕竟只是做个实例,在实际场景中,这种逻辑可能让你云里雾里,防不胜防。

@PayCode(value = "ali",name = "支付宝支付")
@Service
public class AliPay implements IPay {
    @Override
    public void pay() {
        System.out.println("--------发起支付宝支付");
    }
}

@PayCode(value = "jd",name = "京东支付")
@Service(value = "jdPay")
public class JDPay implements IPay{
    @Override
    public void pay() {
        System.out.println("--------发起了京东支付");
    }
}

@PayCode(value = "weiXin",name = "微信支付")
@Service
public class WeiXinPay implements IPay {
    @Override
    public void pay() {
        System.out.println("--------发起了微信支付");
    }
} 
核心处理类

PayService2核心逻辑是继承Spring的ApplicationListener,利用监听事件ContextRefreshedEvent,来实现对各个具体实现类的初步加载
原理是Spring IOC容器加载处理完相应的Bean后,有一个发布事件的动作(ContextRefreshedEvent),其实这是一个Spring IOC 容器给提供的拓展的地方,xdm,讲道理这个东西还是很实用的,无论在日常开发,还是研究框架源码,这种处理机制都很常见,学习一波☺

@Service
public class PayService2 implements ApplicationListener<ContextRefreshedEvent> {
    private static Map<String,IPay> payMap = null;
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = event.getApplicationContext();
        Map<String,Object> beansWithAnno = applicationContext.getBeansWithAnnotation(PayCode.class);
        if (beansWithAnno != null){
            payMap = new HashMap<>();
            beansWithAnno.forEach((key,value) ->{
                String bizType = value.getClass().getAnnotation(PayCode.class).value();
                payMap.put(bizType,(IPay) value);
            });
        }
    }

    public void pay(String code){
        payMap.get(code).pay();
    }
}

当然了,要获取Spring 容器里Bean,对Bean做一些需要的操作,起到随用随取的效果,当然不止这一种用法了。
我很贴心滴,再为大家贴一种写法。
PayService3,和PayService2可以得到一样的效果
继承ApplicationContextAware
ApplicationContextAware接口只有一个方法,如果实现了这个方法,那么Spring创建这个实现类的时候就会自动执行这个方法,把ApplicationContext注入到这个类中,也就是说,spring 在启动的时候就需要实例化这个 class(如果是懒加载就是你需要用到的时候实例化),在实例化这个 class 的时候,发现它包含这个 ApplicationContextAware 接口的话,sping 就会调用这个对象的 setApplicationContext 方法,把 applicationContext Set 进去了。
知识点: 一般我们经常会使用这个类来获取Spring的IOC容器

@Service
public class PayService3 implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private static final String SUFFIX = "Pay";
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void toPay(String payCode){
        ((IPay)applicationContext.getBean(getBeanName(payCode))).pay();
    }
    public String getBeanName(String payCode){
        return payCode + SUFFIX;
    }
}
具体使用类

/**
 * @description:
 * @author: zhanghailang
 * @date: 2022-1-24 14:43
 */
@RestController
public class TestContrller {

    @Autowired
    private PayService2 payService2;

    @Autowired
    private PayService3 payService3;

    @PutMapping(value = "/test/{payCode}")
    public void test(@PathVariable("payCode") String payCode){

//        if ("ali".equals(payCode)) {
//            System.out.println("ali pay start");
//        }
//        if ("jd".equals(payCode)) {
//            System.out.println("jd pay start");
//        }
//        if ("weixin".equals(payCode)) {
//            System.out.println("weixin pay start");
//        }
        //.....

        this.payService2.pay(payCode);
        this.payService3.toPay(payCode);
    }
}

请求结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过上面的演示,大家应该能够看到这种策略模式实现减少if-else的优缺点
优点:代码整洁、解耦,符合开闭原则,职责分明,代码优雅
   缺点:每个实现都需要新增个类,当策略过多的时候,就要考虑使用混合模式来优化策略模式了。



函数式编程


『☺嘿,是不是没想到,这怎么还能用函数式编程吗,且听我为大家稍微的讲解下』

FunctionPayServicePayService4利用@PostConstruct,Supplier<>接口,根据不同的策略,将定义的具体业务操作类FunctionPayService,封装在map里,在使用的时候随用随取即可

/**
 * @description: 具体的业务分类
 * @author: zhanghailang
 * @date: 2022/1/25 17:18
 */
@Service
public class FunctionPayService {
    public String aliPay() {
        System.out.println("ali Pay start");
        return "ali";
    }

    public String weiXinPay() {
        System.out.println("weiXin Pay start");
        return "weinXin";
    }

    public String jdPay() {
        System.out.println("jd Pay start");
        return "jd";
    }
}


/**
 * @description: 使用Lamda 函数式编程减少 if else
 * 参考公众号:https://mp.weixin.qq.com/s/79go9AFZgcnNM7uk_5Yaew
 * @author: zhanghailang
 * @date: 2022/1/25 17:09
 */
@Service
public class PayService4 {

    @Autowired
    private FunctionPayService functionPayService;

    private Map<String, Supplier<String>> payMap = new HashMap<>();

    /**
     * 初始化业务分派逻辑,代替了if-else 部分
     */
    @PostConstruct
    public void dispatcherInit() {
        payMap.put("ali",() -> functionPayService.aliPay());
        payMap.put("weiXin",() -> functionPayService.weiXinPay());
        payMap.put("jd",() -> functionPayService.jdPay());
    }

    public void pay(String payCode){
        this.payMap.get(payCode).get();
    }
}

上述函数式编程的减少if-else的结果和策略模式一样。
函数式编程用起来是真滴好用,有不懂的xdm,建议学习一波,但是不建议滥用,曾经看过一段代码,函数式编程,纯Lamda表达式,套着各种业务逻辑,给我看晕了,强烈不建议在函数式编程里,写大量业务逻辑。

以上就是小弟的拙见,大家新年快乐啦

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值