第一、什么是策略模式
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重if判断问题。
1.环境(Context)角色:持有一个Strategy的引用。
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
第二、策略模式应用场景
比如搭建聚合支付平台的时候,这时候需要对接很多第三方支付接口,比如支付宝、微信支付、小米支付等。
通过传统if代码判断的,后期的维护性非常差!
public String toPayHtml2(String payCode){
if(payCode.equals("ali_pay")){
return "调用支付宝接口...";
}
if(payCode.equals("xiaomi_pay")){
return "调用小米支付接口";
}
if(payCode.equals("yinlian_pay")){
return "调用银联支付接口...";
}
return "未找到该接口...";
}
这时候可以通过策略模式解决多重if判断问题。
第三、策略模式架构图
第四、策略模式案例
1、引入maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
</parent>
<dependencies>
<!-- sprinboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
2、创建一个接口PayStrategy(抽象角色)
/**
* 抽象角色
* 策略类
*/
public interface PayStrategy {
/**
* 共同算法实现骨架
* @return
*/
public String toPayHtml();
}
3、创建具体实现类(AliPayStrategy)
/**
* 支付子类
*/
@Component
public class AliPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用支付接口";
}
}
4、创建具体实现类(XiaoMiPayStrategy)
/**
* 小米实现类
*/
@Component
public class XiaoMiPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用小米接口";
}
}
5、创建一个得到bean对象的工具类(SpringContextUtil)
/**
* 得到bean对象
*
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的回调方法。设置上下文环境
*
* @param 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 <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
}
6、创建一个实体类
@Data
public class PaymentChannelEntity {
/** ID */
private Integer id;
/** 渠道名称 */
private String channelName;
/** 渠道ID */
private String channelId;
/**
* 策略执行beanId
*/
private String strategyBeanId;
}
7、创建一个mapper接口
public interface PaymentChannelMapper {
@Select("
" +
"SELECT id as id ,CHANNEL_NAME as CHANNELNAME ,CHANNEL_ID as CHANNELID,strategy_bean_id AS strategybeanid
" +
"FROM payment_channel where CHANNEL_ID=#{payCode}")
public PaymentChannelEntity getPaymentChannel(String payCode);
}
8、创建一个上下文对象获取对应的实现类
/**
* 上下文
*/
@Component
public class PayContextService {
@Autowired
private PaymentChannelMapper paymentChannelMapper;
@Autowired
private SpringContextUtil springContextUtil;
public String toPayHtml(String payCode){
//验证参数
if(StringUtils.isBlank(payCode)){
return "参数不能为空";
}
//使用该paycode查询
PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
if(paymentChannel==null){
return "该渠道为空...";
}
//获取对应的beanid
String strategyBeanId = paymentChannel.getStrategyBeanId();
if (strategyBeanId==null){
return "beanId为空";
}
//得到对应的bean
PayStrategy payStrategy = springContextUtil.getBean(strategyBeanId, PayStrategy.class);
// 5.执行具体策略算法
return payStrategy.toPayHtml();
}
}
9、创建一个controller层
@RestController
public class PayController {
@Autowired
private PayContextService payContextService;
@RequestMapping("/index")
public String index(String payCode){
return payContextService.toPayHtml(payCode);
}
}
10、创建一个启动类
@SpringBootApplication
@MapperScan("com.yehui.mapper")
public class StartMainApp {
public static void main(String[] args) {
SpringApplication.run(StartMainApp.class);
}
}
11、yml文件
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
password: root
url: jdbc:mysql://localhost:3306/study
username: root
logging:
level:
com.yehui.mapper: debug
启动测试:
访问小米: http://localhost:8080/index?payCode=xiaomi_pay
效果
访问支付: http://localhost:8080/index?payCode=ali_pay
效果
12、相关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='支付渠道 ';
INSERT INTO `payment_channel` VALUES ('4', '支付宝渠道', 'ali_pay', 'aliPayStrategy');
INSERT INTO `payment_channel` VALUES ('5', '小米支付渠道', 'xiaomi_pay', 'xiaoMiPayStrategy');