在平时开发中,有时避免不了使用大量判断,简单处理的话就使用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逻辑拓展
如上,如果后续再加新成员的业务,只需要实现其对应的具体策略类即可,不需要关注其对其他成员的业务是否有影响。
2. 策略模式+工厂模式+模板模式实现不同业务
现在来了新需求,之前成员实现的方法基本一致,但现在要求:“骚斌”实现打印名称,“傻强”实现跳舞,“伟峰”实现打印名称和跳舞,后续随时会有新增成员和新增功能,基于上面的实现,可以在策略总接口中新增跳舞方法,实现如下:
可以看出,在总策略接口中新增“跳舞”方法后,没有该功能的“骚斌”也需要实现它,这个就很不友好了。下面对其进行改造:
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 策略实现
各成员只需实现其对应的策略方法即可。
如下,测试成员功能,对于有具体实现的方法,成员会执行,如果没有具体实现,会抛出异常。
经过上面改造,后面如果新增成员或者新功能实现,新增策略实现即可。这种改造符合开闭原则,适用较为复杂的逻辑判断。