前言
在项目开发中,常遇到同一行为针对不同类型做不同的处理逻辑,在类型少、逻辑简单时,常使用if else 或者switch,但当业务增加类型,改变逻辑时,就显得可维护性不高,因此需要结合业务,使用策略模式消除if-else,易维护,可扩展。
if-else或switch
本文以之前项目中做过,较为简单的SSL证书为例。
在产品类型只有DV、EV时,使用if-else看起来就够了
@Service
public class ApplySSLService {
public void applySSL(OrderDetail orderDetail) {
String productType = orderDetail.getProductType();
if ("DV".equals(productType)) {
//TODO dv处理订单
} else if ("EV".equals(productType)) {
//TODO ev处理订单
}
}
}
但当产品类型再添加OV时,又需要再添加一个if-else
@Service
public class ApplySSLService {
public void applySSL(OrderDetail orderDetail) {
String productType = orderDetail.getProductType();
if ("DV".equals(productType)) {
//TODO dv处理订单
} else if ("EV".equals(productType)) {
//TODO ev处理订单
} else if ("OV".equals(productType)) {
//TODO ov处理订单
}
}
}
这么处理的话,导致代码不灵活,下次新增功能时,需要修改现有代码(增加if分支)
优化:注解+策略模式+简单工厂
定义注解,针对类型标记
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SSLType {
String value() default "DV";
}
定义处理请求的统一接口
public interface IApplySSLService {
void notify(OrderDetail orderDetail);
}
针对不同类型实现接口,使用注解
@Component
@SSLType(value = "DV")
public class SSLDVService implements IApplySSLService {
@Override
public void notify(OrderDetail orderDetail);
//TODO
}
}
@Component
@SSLType(value = "EV")
public class SSLEVService implements IApplySSLService {
@Override
public void notify(OrderDetail orderDetail);
//TODO
}
}
定义工厂类
@Component
public class SpringUtil implements ApplicationContextAware {
protected static ApplicationContext context = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}
@Component
@DependsOn("springUtil")
public class ApplySSLFactory {
private static Map<String, IApplySSLService > REQUEST_MAP = Maps.newHashMap();
public ApplySSLRequestFactory() {
Map<String, Object> beanMap = SpringUtil.getApplicationContext().getBeansWithAnnotation(SSLType .class);
for (Object applySSL : beanMap.values()) {
SSLType annotation = applySSL.getClass().getAnnotation(SSLType .class);
REQUEST_MAP.put(annotation.value(), (IApplySSLService ) applySSL);
}
}
public static IApplySSLService get(String productType) {
return REQUEST_MAP.get(productType);
}
}
使用工厂类获取,处理逻辑
public void applySSL(OrderDetail orderDetail) {
String productType = orderDetail.getProductType();
IApplySSLService iApplySSLService = ApplySSLFactory.get(productType);
iApplySSLService.notify(orderDetail);
}
策略模式
通过上文可以看出,策略模式由一下角色构成:
- 抽象策略角色:一般由抽象类或接口承担,给出具体策略角色需要实现的接口
- 具体策略角色:实现封装具体的算法或行为
- 场景角色:持有抽象策略类引用,使用方
策略模式的功能是把具体的业务算法实现,从具体的业务处理里独立出来,把他们实现为单独的类,从而形成一系列的算法,并使他们可以相互替换。
策略模式的重心在不是如何实现算法,而是组织、调用他们,从而使程序结构更加灵活,易于维护和扩展。
策略模式是开闭原则的体现,开闭原则讲一个软件应对扩展开放、对修改关闭,策略模式在新增策略时,不会影响其他类的修改,增加了扩展性,也就是对扩展开放。对于场景角色来说,只依赖抽象,而不依赖于具体实现,所以对修改是关闭的。
总结
通过注解+策略+简单工厂模式,消除了if-else语句,增加了代码的灵活性,当新增功能时,也不用修改原有代码,直接实现接口即可,这也符合开闭原则,使得代码更易于维护,易于理解
~~以上为笔者个人理解,由于水平有限,如有疏漏,望多多指教 ~~