Java 策略模式
2021-02-09 本文已影响0人
索性流年
一句话总结策略模式
- 主要是一对多,要是一个API需要多种实现方法,便用策略模式
什么是策略模式?
- 策略模式就是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多if重判断问题。
实现过程
- 定义策略接口->实现不同的策略类->利用多态或其他方式调用策略. .
1.环境(Context)角色:持有一个Strategy的引用。。
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此
出所有的具体策略类所需的接口。。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。。
优点
- 维护性增强,扩展性增强,提高可读性。
缺点
- 后期维护不通的策略类非常多、代码量增大
总结
- 优点大于缺点。
案例聚合支付
前提
-
如若正常聚合支付,一个接口方法中会有多重判断,调用支付宝,调用微信,调用银联。。。。
如若想要扩展内容首先就要更改这些判断,而这里面的每一个方法都有大量逻辑,一不小心就会牵一发而动全身,而使用策略模式的目的就是增强接口扩展性 -
定义支付算法共同骨架,PayStrategy
/*
* 共同算法定义骨架
*
* */
public interface PayStrategy {
/*共同算法骨架*/
public String toPayhtml();
}
- 定义对应实现类这里只是简单模拟返回
/*阿里支付算法*/
@Component
public class AliPayStrategy implements PayStrategy {
@Override
public String toPayhtml() {
return "调用支付宝支付方法";
}
}
/*银联支付算法*/
@Component
public class YinLianPayStrategy implements PayStrategy {
@Override
public String toPayhtml() {
return "调用银联支付方式";
}
}
- 新建数据库用于存储支付方式以及对应实现类,创建Dao层获取数据这里是用Mybatis实现Dao层
@Component
@Mapper
public interface PaymentChannelMapper {
@Select("SELECT * FROM payment_channel AS pay WHERE pay.payId = #{payCode}")
PaymentChannelEntity getPaymentChannel(String payCode);
}
//实体类
public class PaymentChannelEntity {
private String id;
private String payId;
private String payType;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPayId() {
return payId;
}
public void setPayId(String payId) {
this.payId = payId;
}
public String getPayType() {
return payType;
}
public void setPayType(String payType) {
this.payType = payType;
}
}
- 获取SpringIOC容器工具类
/*使用Bend对象获取Spring容器中对应的类*/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
/*获取context上下文*/
public static ApplicationContext getApplicationContext(){
return context;
}
/*通过name获取Bean*/
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
/*通过类名获取Bean*/
public static <T>T getBean(Class<T> className){
return getApplicationContext().getBean(className);
}
/*通过name,以及Class返回指定Bean*/
public static <T>T getBean(String neme, Class<T> className){
return getApplicationContext().getBean(neme,className);
}
}
新建.class作用于获取对象实现类
@Component
public class PayContextStrategy {
@Autowired
public PaymentChannelMapper paymentChannelMapper;
@Autowired
public SpringUtils springUtils;
public PayContextStrategy() {
super();
}
public String toPayHtml(String payCode){
System.err.println(payCode);
// 使用PayCode查询数据库获取Bendid
PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
// 获取bindid,使用spring容器获取实例方法
if (paymentChannel == null){
return "没有该渠道信息";
}
String strategyBeanId = paymentChannel.getPayType();
System.err.println(strategyBeanId);
if (StringUtils.isEmpty(strategyBeanId)){
return "该渠道配置ben配置";
}
PayStrategy payStrategy = springUtils.getBean(strategyBeanId,PayStrategy.class);
return payStrategy.toPayhtml();
};
}
新建.class 控制器作用于接口测试
@RestController
public class PayController {
@Autowired
private PayContextStrategy contextStrategy;
@GetMapping("/toPayHtml")
public String toPayHtml(String payCode){
if (StringUtils.isEmpty(payCode)){
return "渠道code不能为空";
}
return contextStrategy.toPayHtml(payCode);
}
}
总结
- 如若需要接入其他支付方式,则直接创建该支付的实现类存入数据库中,无需改动其他逻辑,这个使用数据库只是例子,可以使用枚举
案例思路
- 首先建立支付接口公共骨架,用于后期动态获取实现类→使用数据库存储实现类对象以及类型→查询数据库动态获取实现类→使用Spring获取支付类的具体实现→使用接口调用相关方法测试