为什么需要使用设计模式
使用策略模式进行对代码的优化,提高代码的复用性等
什么是策略模式
策略模式是对策略算法的包装,将不同的算法进行拆分开,委派给不同的对象管理,最终可以解决优化多重if判断问题
1.环境(Context)角色:持有一个Strategy的引用。
2.Strategy接口:定义一个Strategy接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
定义策略接口->实现不同的策略类->利用多态或其他方式调用策略
为什么叫做策略模式
每个if判断都可以理解为就是一个策略。
策略模式优缺点
优点
算法可以自由切换(高层屏蔽算法,角色自由切换)
避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)
扩展性好(可自由添加取消算法 而不影响整个功能)
缺点
策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)
策略模式应用场景
聚合支付平台
比如搭建聚合支付平台的时候,这时候需要对接很多第三方支付接口,比如支付宝、微信支付、小米支付等。
通过传统if代码判断的,后期的维护性非常差!
public String toPayHtml2(String payCode){
|
这时候可以通过策略模式解决多重if判断问题。
策略模式架构图
下边通过两种方式进行实现
①通过枚举类
②通过数据库查询
定义PayStrategy(抽象角色)
package com.liangzai.strategy;
/**
* @author leiliang
* @version 1.0
* @Description 定义共同的借口
* @date 2021/3/11 15:48
*/
public interface PayStrategy {
public String toPayHtml();
}
ConcreteStrategy (具体实现策略类)
package com.liangzai.strategy.impl;
import com.liangzai.strategy.PayStrategy;
import org.springframework.stereotype.Component;
/**
* @author leiliang
* @version 1.0
* @Description 支付宝具体的策略类
* @date 2021/3/11 15:50
*/
@Component
public class AliPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "支付宝支付。。。";
}
}
package com.liangzai.strategy.impl;
import com.liangzai.strategy.PayStrategy;
import org.springframework.stereotype.Component;
/**
* @author leiliang
* @version 1.0
* @Description 微信支付具体的策略类
* @date 2021/3/11 15:50
*/
@Component
public class WechatPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "微信支付。。。";
}
}
PayContextService (上下文)
package com.liangzai.context;
import com.liangzai.entity.PaymentChannelEntity;
import com.liangzai.factory.StrategyFactory;
import com.liangzai.mapper.PaymentChannelMapper;
import com.liangzai.strategy.PayStrategy;
import com.liangzai.utils.SpringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author leiliang
* @version 1.0
* @Description 通过上下文获取具体的策略类
* @date 2021/3/11 16:05
*/
@Component
public class PayContextStrategy {
@Autowired
PaymentChannelMapper paymentChannelMapper;
/**
* 枚举类的方式
* @param payCode
* @return
*/
public String toPayHtml1(String payCode) {
if (StringUtils.isEmpty(payCode)) {
return "payCode 不能为空";
}
//使用策略工厂获取具体实现类 工厂进行初始化
PayStrategy payStrategy = StrategyFactory.getPayStrategy(payCode);
if (payStrategy == null) {
return "没有找到具体策略实现";
}
return payStrategy.toPayHtml();
}
/**
* 数据库的方式
* @param payCode
* @return
*/
public String toPayHtml(String payCode) {
if (StringUtils.isEmpty(payCode)) {
return "payCode 不能为空";
}
//通过数据库方式获取
PaymentChannelEntity channel = paymentChannelMapper.getPaymentChannel(payCode);
if (channel == null) {
return "没有查询到支付渠道";
}
//获取数据库中bean的id
String channelId = channel.getStrategyBeanId();
if (StringUtils.isEmpty(channelId)){
return "没有查询到支付渠道策略类";
}
PayStrategy payStrategy = (PayStrategy) SpringUtils.getBean(channelId);
return payStrategy.toPayHtml();
}
}
SpringUtils
package com.liangzai.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring工具类
*/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
}
枚举类
package com.liangzai.enums;
public enum PayEnumStrategy {
/**
* 支付宝支付
*/
ALI_PAY("com.liangzai.strategy.impl.AliPayStrategy"),
/**
* 微信支付
*/
WECHAT_PAY("com.liangzai.strategy.impl.WechatPayStrategy");
PayEnumStrategy(String className) {
this.setClassName(className);
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
/**
* class完整地址
*/
private String className;
}
StrategyFactory
package com.liangzai.factory;
import com.liangzai.enums.PayEnumStrategy;
import com.liangzai.strategy.PayStrategy;
/**
* @author leiliang
* @version 1.0
* @Description 策略工厂 获取不同的策略实现类
* @date 2021/3/11 15:59
*/
public class StrategyFactory {
public static PayStrategy getPayStrategy(String strategyType) {
try {
//1.获取具体的策略实现类地址 通过反射机制获取类名
String className = PayEnumStrategy.valueOf(strategyType).getClassName();
return (PayStrategy) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
数据库访问层
相关SQL语句
DROP TABLE IF EXISTS `payment_channel`; CREATE TABLE `payment_channel` ( `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', `CHANNEL_NAME` varchar(32) NOT NULL COMMENT '渠道名称', `CHANNEL_ID` varchar(32) NOT NULL COMMENT '渠道ID', `strategy_bean_id` varchar(255) DEFAULT NULL COMMENT '策略执行beanid', PRIMARY KEY (`ID`,`CHANNEL_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='支付渠道 ';
-- ---------------------------- -- Records of payment_channel -- ---------------------------- INSERT INTO `payment_channel` VALUES ('4', '支付宝渠道', 'ali_pay', 'aliPayStrategy'); INSERT INTO `payment_channel` VALUES ('5', '小米支付渠道', 'xiaomi_pay', 'xiaoMiPayStrategy'); |
数据库访问层
@Data
public interface PaymentChannelMapper {
|
Controller请求入口
package com.liangzai.controller;
import com.liangzai.context.PayContextStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author leiliang
* @version 1.0
* @Description
* @date 2021/3/11 16:20
*/
@RestController
public class PayController {
@Autowired
PayContextStrategy payContextStrategy;
@RequestMapping("/pay")
public String toPayHtml(String payCode){
return payContextStrategy.toPayHtml(payCode);
}
}
执行流程:
枚举方式
paycontroller---->context上下文---->策略工厂通过反射获取类名------>执行PayStrategy接口
数据库方式
paycontroller---->context上下文---->获取数据库中bean的id通过spring.getBean获取类名------>执行PayStrategy接口