代码逻辑臭又长,巧用SPI来优化

泛滥的 if-else 实现

现实处理逻辑中,我们经常会遇到这样代码逻辑 :

if(type.equal("A")){
 doA();
} else if(type.equal("B")){
 doB();
} else if(...){
 ...
}

这样写起来,的确得心应手,如行云流水,但是,在大咖面前,代码评审又怎么拿的出手?该怎么办呢?也许spi能解决这样的问题。更多内容,请关注微信公众号: 白白家族


什么是spi

SPI 英文全称为(Service Provider Interface) ,是JDK内置的一种服务提供发现机制。在数据库DriverManager、Spring等实现都用到了SPI机制。JavaSPI 的本质是基于策略模式,根据接口配置文件,以接口的编程的形式对外提供服务。

SPI原理机制

当服务的提供者提供了服务接口的实现后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过META-INF/services/里的配置文件类名,装载并实例化。

应用场景

在oop思想中,模块之间是基于借口编程,也就是说,模块之间对实现类不进行硬编码,而是在运行时,动态寻找服务实现机制,这也就需要一种服务发现机制,而spi正是提供了这种全套的解决方案,可以大幅提高代码代码规范以及简洁度。

实践举例

场景举例:一个charge接口,根据传递commandName 参数的不同值,动态实现不同的功能,例如,commandName 为 cashCharge的时候,实现 CashCharge 类的功能,当 commandName 为AssureCharge的时候,实现 AssureCharge 类的功能,避免用 if-else的方式实现;以下是具体操作步骤:

1. 定义一组接口;

public interface Charge {
 Boolean process(String args);
 String getType();
}

2. 定义接口的一个或多个实现 :cashCharge 和assureCharge 的实现

@Service("cashChargeHandler")
public class CashChargeHandler implements Charge {
 @Override
 public Boolean process(String args){
 System.out.println("I am Cash");
 return true;
 }
 @Override
 public String getType() {
 return "cashCharge";
 }
}
@Service("assureChargeHandler")
public class AssureChargeHandler implements Charge {
 @Override
 public Boolean process(String args){
 System.out.println("I am assure");
 return true;
 }
 @Override
 public String getType(){
 return "assureCharge";
 }
}

3. 添加配置文件

在src/main/resources/ 下建立/META-INF/services 目录,

3.1 创建 xxx.xxx.Charge 文件(文件名为接口文件的全路径名)

3.2 添加文件内容:(实现类的全路径名)

xxx.AssureChargeHandler

xxx.CashChargeHandler

4. 使用ServiceLoader 来加载配置文件中指定的实现

public class ConsumeFactory implements ApplicationContextAware {
 private ApplicationContext applicationContext;
 private Map<String,Consume> consumeMap;
 public ConsumeFactory() {
 consumeMap = new ConcurrentHashMap<>();
 }
 @PostConstruct
 public void init(){
 ServiceLoader<Consume> operations = ServiceLoader.load(Cosume.class);
 Iterator<Consume> operationIterator = operations.iterator();
 while(operationIterator.hasNext()){
 Consume consume = operationIterator.next();
 consumeMap.put(consume.getType(),applicationContext.getBean(consume.getClass()));
 }
 }
 public Consume findConsumeType(String consumeType){
 if(consumeMap.containsKey(consumeType)){
 return consumeMap.get(consumeType);
 }
 return null;
 }
 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeanException {
 this.applicationContext = applicationContext;
 }
 

5. 实现方式

5.1 设置引用

@Resource
private ConsumeFactory consumeFactory;

5.2 根据transType 参数动态运行,确定不同类

String commandName = "cashCharge";
Consume consumeHandler = consumeFactory.findConsumeType(commandName);
consumeHandler.process("");

5.3 输出结果:

I am Cash

更过内容请关注微信公众号: 白白家族

或扫描以下微微吗:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值