样例所有代码可以github.com/WeiXiao-Hyy…获取
需求
- 接入支付宝/微信 第三方支付方式 -> 策略模式
- 为上层提供调用接口 -> 门面模式(Facade)
- 为了避免频繁改动门面模式代码 -> 工厂模式
- 为了减少频繁地new对象 -> 享元模式
接入门面模式之后的问题
public String pay(Order order, Integer payType) {
switch (payType) {
case 1:
AlipayStrategy alipayStrategy = new AlipayStrategy();
PayContext alipayContext = new PayContext(alipayStrategy);
return alipayContext.execute(order);
case 2:
WechatStrategy wechatStrategy = new WechatStrategy();
PayContext wechatContext = new PayContext(wechatStrategy);
return wechatContext.execute(order);
default:
throw new UnsupportedOperationException("Pay Type not supported!");
}
}
- 频繁地进行类的创建,会导致minor GC,这里需要使用工厂模式进行封装
- 一般会很少修改门面模式中的代码
对@Component的理解,能用则用,但是在面对封装性和安全性就需要使用工厂模式进行封装
// 这样封装之后,扩展性也会更佳
@Component
public class PayFacade {
@Autowired
private PayContextFactory contextFactory;
public String pay(Order order, Integer payType) {
PayContext context = contextFactory.getContext(payType);
return context.execute(order);
}
}
享元模式带来的问题,是否需要使用双重检验方法
unsharedFlyWeight:不能共享的对象,每次使用都需要重新new一个新的对象
@Component
public class PayContextFactory extends AbstractPayContextFactory<PayContext> {
//享元模式
private static final Map<String, PayContext> payContexts = new ConcurrentHashMap<>();
@Override
public PayContext getContext(Integer payType) {
StrategyEnum strategyEnum =
payType == 1 ? StrategyEnum.alipay :
payType == 2 ? StrategyEnum.wechat :
null;
if (Objects.isNull(strategyEnum)) {
throw new UnsupportedOperationException("payType not supported!");
}
//尝试从map中获取Context
PayContext context = payContexts.get(strategyEnum.name());
//第一次调用
if (Objects.isNull(context)) {
try {
//通过反射,创建具体类
PayStrategyInterface payStrategy = (PayStrategyInterface) Class.forName(strategyEnum.getValue()).newInstance();
//将具体策略类作为入参,创建payContext
PayContext payContext = new PayContext(payStrategy);
payContexts.put(strategyEnum.name(), payContext);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new UnsupportedOperationException("get strategy failed!");
}
}
return payContexts.get(strategyEnum.name());
}
}