策略设计模式(Strategy Pattren)。当系统中有很多具有相同行为的类时。可以使用策略模式,使用一个类将它们封装起来统一调用,在不同的场景下调用不同的类来完成这个功能。
常用实现结构图如下:
策略设计模式在实际应用中还是非常广泛的。不如说系统登录(账号/密码,邮箱/密码,手机号/验证码,以及第三方登录),在线支付(支付宝,微信,银行卡等等),以及加密算法的配置。
首先还是来举个栗子,以支付流程为例:
①先创建支付策略接口:
public interface PayStrategy {
/**
* 在线支付接口
* @param payerId 付款方ID
* @param money 付款金额
* @param payeeId 收款方ID
*/
void pay(String payerId,BigDecimal money ,String payeeId);
}
② 创建支付宝支付策略和微信支付策略:
public class AlipayStrategyImpl implements PayStrategy {
@Override
public void pay(String payerId, BigDecimal money, String payeeId) {
System.out.println(String.format("%s正在使用【支付宝】给%s付款%f元",payerId,payeeId,money.doubleValue()));
}
}
public class WeChatPayStrategyImpl implements PayStrategy{
@Override
public void pay(String payerId, BigDecimal money, String payeeId) {
System.out.println(String.format("%s正在使用【微信支付】给%s付款%f元",payerId,payeeId,money.doubleValue()));
}
}
③ 创建策略使用客户端Client
public class Client {
private static Map<PayType,PayStrategy> payStrategys ;
static {
payStrategys = new ConcurrentHashMap<>(2);
payStrategys.put(PayType.ALI_PAY,new AlipayStrategyImpl());
payStrategys.put(PayType.WECHAT_PAY,new WeChatPayStrategyImpl());
}
public void payMoney(PayType payType, String payerId, BigDecimal money, String payeeId){
PayStrategy payStrategy = Objects.requireNonNull(payStrategys.get(payType),"未找到合适的付款策略");
payStrategy.pay(payerId,money,payeeId);
}
public static enum PayType{
/**
* 支付宝支付方式
*/
ALI_PAY,
/**
* 微信支付方式
*/
WECHAT_PAY,
}
}
④ 测试
public static void main(String[] args) {
Client client = new Client();
client.payMoney(PayType.ALI_PAY,"001",BigDecimal.valueOf(100),"002");
}
输出结果:
001正在使用【支付宝】给002付款100.000000元
再来看一下策略模式在源码中的应用。例如spring容器中bean的初始化策略。
bean的实例化策略在BeanFactroy#getBean的过程中会使用到。
AbstractAutowireCapableBeanFactory#instantiateBean()源码如下:
/**
* Instantiate the given bean using its default constructor.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return a BeanWrapper for the new instance
*/
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
//获取bean实例化策略,调用instantiate(mbd, beanName, parent)来实例化一个bean
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
可以看到策略模式的实现不仅仅可以使用implement。还可以配合使用extend 。所以说设计模式相当于武功招式。是死板的,但是在使用时可以根据实际应用场景进行适当变化,并配合其他的设计模式。不局限于一招一式。这才是一个武侠高手的必备素养。