在平时开发中,有时避免不了使用大量判断,简单处理的话就使用if...else...了,但过多层的if else对于性能有很大的开销,而且业务复杂的话,耦合太重,对于后期的拓展也不是很友好,所以使用策略模式。

1. 策略+工厂实现相同业务抽象

策略模式:一种解耦的方法,它对算法进行封装,使得算法的调用和算法本身分离。使用策略模式客户端代码不需要调整,算法之间可以互相替换,因为不同的算法实现的是同一个接口。策略模式是一种对象行为型模式。策略模式符合“开闭原则”。

策略模式包括如下角色:

  • Context :环境类

  • Strategy:抽象策略类

  • ConcreteStrategy:具体策略类

下面简单抽象下业务逻辑:

String name = "shaqiang";

if(name.equals("saobin")){
    System.out.println("I am SaoBin");
}else if(name.equals("shaqiang")){
    System.out.println("I am ShaQiang");
}else if(name.equals("weifeng")){
    System.out.println("I am WeiFeng");
}

有成员“骚斌”、“傻强”、“伟峰”···,其执行逻辑基本一样,基于策略模式对其进行改造:

1.1 定义策略接口

将成员的业务方法抽象为统一的策略接口。其中 InitializingBean 接口来自Spring框架,用于实现环境的统一工厂。

import org.springframework.beans.factory.InitializingBean;

/**
 * 策略总接口*/
public interface NameHandler extends InitializingBean {
    /**
     * 输出名称
     * @param name
     */
    public void myName(String name);

}

1.2 实现策略工厂

此处的工厂即策略模式下的 “环境类” 要素,功能为根据不同的name找到其对应的不同的策略实现,实现方法为将实现NameHandler接口的类都装载到strategyMap里,除使用工厂实现外,也可以使用枚举+代理实现。

import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 工厂设计模式*/
public class NameSetFactory {

    private static Map<String, NameHandler> strategyMap = new HashMap<>();

    /**
     * 根据name获取对应的handler实现
     * @param name
     * @return
     */
    public static NameHandler getInvokeStrategyMap(String name){
        return strategyMap.get(name);
    }

    /**
     * 注册
     * @param name
     * @param handler
     */
    public static void register(String name, NameHandler handler){
        if(StringUtils.isEmpty(name)||null == handler){
            return;
        }
        strategyMap.put(name,handler);
    }
}

1.3 为各成员实现各自的具体策略实现类

将各自实现类声明为组件(用于维护工厂),org.springframework.beans.factory.InitializingBean#afterPropertiesSet内部实现工厂注册。

import org.springframework.stereotype.Component;

/**
 * saobin策略实现*/
@Component
public class SaoBinHandler implements NameHandler {

    /**
     * 输出名称
     * @param name
     */
    @Override
    public void myName(String name) {
        System.out.println("I am SaoBin");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        NameSetFactory.register("saobin",this);
    }
}
import org.springframework.stereotype.Component;

/**
 * shaqiang策略实现*/
@Component
public class ShaQiangHandler implements NameHandler {

    /**
     * 输出名称
     * @param name
     */
    @Override
    public void myName(String name) {
        System.out.println("I am ShaQiang");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        NameSetFactory.register("shaqiang",this);
    }
}
import org.springframework.stereotype.Component;

/**
 * weifeng策略实现*/
@Component
public class WeiFengHandler implements NameHandler {

    /**
     * 输出名称
     * @param name
     */
    @Override
    public void myName(String name) {
        System.out.println("I am WeiFeng");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        NameSetFactory.register("weifeng",this);
    }
}

1.4 新增if逻辑拓展

策略模式+工厂模式+模板模式彻底取代 if...else..._spring

 如上,如果后续再加新成员的业务,只需要实现其对应的具体策略类即可,不需要关注其对其他成员的业务是否有影响。

2. 策略模式+工厂模式+模板模式实现不同业务

现在来了新需求,之前成员实现的方法基本一致,但现在要求:“骚斌”实现打印名称,“傻强”实现跳舞,“伟峰”实现打印名称和跳舞,后续随时会有新增成员和新增功能,基于上面的实现,可以在策略总接口中新增跳舞方法,实现如下:

策略模式+工厂模式+模板模式彻底取代 if...else..._模板模式_02

 策略模式+工厂模式+模板模式彻底取代 if...else..._模板模式_03

 可以看出,在总策略接口中新增“跳舞”方法后,没有该功能的“骚斌”也需要实现它,这个就很不友好了。下面对其进行改造:

2.1 模板设计模式改造总策略接口

将原先的接口改造为抽象类,实现模板模式,所有的功能在类中定义,子类要实现具体功能,重写即可。

import org.springframework.beans.factory.InitializingBean;

/**
 * 策略抽象类(模板)
 */
public abstract class AbstractNameHandler implements InitializingBean {
    /**
     * 输出名称
     * @param name
     */
     public void myName(String name){
         throw new UnsupportedOperationException();
     };

    /**
     * 跳舞
     * @param name
     */
    public void dance(String name){
        throw new UnsupportedOperationException();
    };

}

2.2 策略实现

各成员只需实现其对应的策略方法即可。

策略模式+工厂模式+模板模式彻底取代 if...else..._ide_04

如下,测试成员功能,对于有具体实现的方法,成员会执行,如果没有具体实现,会抛出异常。

策略模式+工厂模式+模板模式彻底取代 if...else..._ide_05

 经过上面改造,后面如果新增成员或者新功能实现,新增策略实现即可。这种改造符合开闭原则,适用较为复杂的逻辑判断。