使用注解+策略模式+简单工厂模式,减少if或switch语句

871 阅读3分钟

前言

在项目开发中,常遇到同一行为针对不同类型做不同的处理逻辑,在类型少、逻辑简单时,常使用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);
}

策略模式

通过上文可以看出,策略模式由一下角色构成:

  1. 抽象策略角色:一般由抽象类或接口承担,给出具体策略角色需要实现的接口
  2. 具体策略角色:实现封装具体的算法或行为
  3. 场景角色:持有抽象策略类引用,使用方

策略模式的功能是把具体的业务算法实现,从具体的业务处理里独立出来,把他们实现为单独的类,从而形成一系列的算法,并使他们可以相互替换。

策略模式的重心在不是如何实现算法,而是组织、调用他们,从而使程序结构更加灵活,易于维护和扩展。

策略模式是开闭原则的体现,开闭原则讲一个软件应对扩展开放、对修改关闭,策略模式在新增策略时,不会影响其他类的修改,增加了扩展性,也就是对扩展开放。对于场景角色来说,只依赖抽象,而不依赖于具体实现,所以对修改是关闭的。

总结

通过注解+策略+简单工厂模式,消除了if-else语句,增加了代码的灵活性,当新增功能时,也不用修改原有代码,直接实现接口即可,这也符合开闭原则,使得代码更易于维护,易于理解

~~以上为笔者个人理解,由于水平有限,如有疏漏,望多多指教 ~~