泛滥的 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
更过内容请关注微信公众号: 白白家族
或扫描以下微微吗: