策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。--维基百科 在项目中时常会用到策略模式的场景,比如业务中需要支付,但是有多个支付渠道,那如何对上层业务暴露"统一口径"(接口)呢,下面结合代码说明, 首先定义支付接口:
public interface Pay{ // 具体支付业务逻辑 public void toPay(); // 支付类型 public Integer payType();}
AliPay:
public class AliPay implements Pay{ public void toPay(){ ... } public Integer payType(){ // 返回支付类型枚举 return 1; }}
WxPay:
public class WxPay implements Pay{ public void toPay(){ ... } public Integer payType(){ // 返回支付类型枚举 return 2; }}
不同的实现已经好了,需要在上层业务中传入不同的支付类型,调用具体的实现,结合在Spring项目中使用方式:
@Componentpublic class PayTypeUtil implements InitializingBean{ @Autowired private List<Pay> payList; private static final Map<Integer,Pay> payMap = Maps.newHashMap(); @Override public void afterPropertiesSet() throws Exception { for (Pay pay : payList) { payMap.put(pay.payType(),pay); } } public Pay getPayService(Integer payType){ return payMap.get(payType); } public static void putService(Pay pay){ payMap.put(pay.payType(),pay); }}
直接使用 PayTypeUtil
的getPayService方法传入不同的支付类型便可得到具体的实现,上面借助了Spring中的 InitializingBean
接口实现了在bean初始化时,加载 Pay
所有的实现类(InitializingBean可参考文章https://blog.csdn.net/BAT_os/article/details/81844985),难道只有这种方法才可以实现么,当然不是,下面再介绍两种方法:
1. 在META-INF/services中添加文件com.xxx.BaseApplication,并写入com.xxx.AliPay,com.xxx.WxPay2. 获取Pay所有实现,并注册ServiceLoader<Pay> payLoader = ServiceLoader.load(Pay.class);for(Pay pay:payLoader){ PayTypeUtil.putService(pay);}
@PostConstruct
(与之对应的是@PreDestroy),作用于Servlet生命周期的注解,实现Bean初始化之前的自定义操作,关于 @PostConstruct
可参考https://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html,具体代码:public class AliPay implements Pay{ @PostConstruct public void init(){ PayTypeUtil.putService(this); } public void toPay(){ ... } public Integer payType(){ // 返回支付类型枚举 return 1; }}public class WxPay implements Pay{ @PostConstruct public void init(){ PayTypeUtil.putService(this); } public void toPay(){ ... } public Integer payType(){ // 返回支付类型枚举 return 2; }}
以上简单说明策略模式的用法,根据实际的业务场景结合使用.