1.为什么要使用设计模式
使用设计模式可以重构整体架构代码、提高代码复用性、扩展性、减少代码冗余
2.什么是策略模式
将算法的责任和本身分割开,委派给不同的对象进行管理,最终解决多重if判断的问题
3.策略模式角色
1.环境角色:context上下文,客户端通过上下文获取具体的策略
2.抽象策略:定义共同行为方法的接口
3.具体策略:不同的策略不同的实现
4.通过枚举加工厂实现策略模式
链接:https://pan.baidu.com/s/1eDKSaH5njISprY3DMqMcuQ
提取码:p29b
1)pom依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<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>
</dependencies>
2)抽象策略
public interface PayStrategy {
/**
* 共同方法的行为
* @return
*/
String toPayHtml();
}
3)具体策略
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;
@Component
public class AlipayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用支付宝接口...AliPayStrategy";
}
}
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;
@Component
public class WeChatPayStrategy implements PayStrategy {
public String toPayHtml() {
return "调用微信支付接口...WeChatPayStrategy";
}
}
4)工厂
import com.demo.enumeration.PayEnumStrategy;
import com.demo.strategy.PayStrategy;
public class StrategyFactory {
/**
* 通过工厂获取具体的策略
*/
public static PayStrategy getPayStrategy(String strategyType) {
try {
String className = PayEnumStrategy.valueOf(strategyType).getClassName();
PayStrategy payStrategy = (PayStrategy)Class.forName(className).newInstance();
return payStrategy;
} catch (Exception e) {
return null;
}
}
}
5)枚举
public enum PayEnumStrategy {
/**
* 支付宝支付
*/
ALI_PAY("com.demo.strategy.impl.AlipayStrategy"),
/**
* 微信支付
*/
WECHAT_PAY("com.demo.strategy.impl.WeChatPayStrategy");
PayEnumStrategy(String className) {
this.setClassName(className);
}
private String className;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
6)环境角色上下文
import com.demo.factory.StrategyFactory;
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;
@Component
public class PayContextStrategy {
/**
* 通过上下文获取具体的策略
*/
public String toPayHtml(String payCode) {
PayStrategy payStrategy = StrategyFactory.getPayStrategy(payCode);
if (payStrategy == null) {
return "没有找到具体的实现策略";
}
return payStrategy.toPayHtml();
}
}
7)控制层
import com.demo.context.PayContextStrategy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class PayController {
@Resource
private PayContextStrategy payContextStrategy;
/**
* 调用支付接口
*/
@GetMapping("/toPayHtml")
public String toPayHtml(String payCode) {
return payContextStrategy.toPayHtml(payCode);
}
}
8)启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
9)测试
http://localhost:8080/toPayHtml?payCode=ALI_PAY
5.通过数据库实现策略模式
链接:https://pan.baidu.com/s/1sHYlTzTL2CZOn3_5FYfruw
提取码:bqjv
1)数据库
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50727
Source Host : localhost:3306
Source Schema : design_pattern
Target Server Type : MySQL
Target Server Version : 50727
File Encoding : 65001
Date: 18/02/2022 16:49:34
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for payment_channel
-- ----------------------------
DROP TABLE IF EXISTS `payment_channel`;
CREATE TABLE `payment_channel` (
`id` int(11) NOT NULL,
`channel_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`channel_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`strategy_bean_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of payment_channel
-- ----------------------------
INSERT INTO `payment_channel` VALUES (1, '支付宝支付', 'alipay', 'alipayStrategy');
INSERT INTO `payment_channel` VALUES (2, '微信支付', 'wechat', 'weChatPayStrategy');
SET FOREIGN_KEY_CHECKS = 1;
2)pom依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</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>
<!-- mysql 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
3)yml
###服务启动端口号
server:
port: 8080
spring:
###数据库相关连接
datasource:
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/design_pattern?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
####打印MyBatias日志
logging:
level:
### 开发环境使用DEBUG 生产环境info或者error
com.demo.mapper: DEBUG
4)渠道Entity
import lombok.Data;
@Data
public class PaymentChannelEntity {
/**
* ID
*/
private Integer id;
/**
* 渠道名称
*/
private String channelName;
/**
* 渠道ID
*/
private String channelId;
/**
* 策略执行beanId
*/
private String strategyBeanId;
}
5)渠道Mapper
import com.demo.entity.PaymentChannelEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@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}")
PaymentChannelEntity getPaymentChannel(String payCode);
}
6)抽象策略
public interface PayStrategy {
/**
* 共同方法的行为
* @return
*/
String toPayHtml();
}
7)具体策略
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;
@Component
public class AlipayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用支付宝接口...AliPayStrategy";
}
}
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;
@Component
public class WeChatPayStrategy implements PayStrategy {
public String toPayHtml() {
return "调用微信支付接口...WeChatPayStrategy";
}
}
8)spring上下文工具类
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@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);
}
}
9)环境角色Context上下文
import com.demo.entity.PaymentChannelEntity;
import com.demo.mapper.PaymentChannelMapper;
import com.demo.strategy.PayStrategy;
import com.demo.utils.SpringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class PayContextStrategy {
@Resource
private PaymentChannelMapper paymentChannelMapper;
/**
* 通过上下文获取具体的策略
*/
public String toPayHtml(String payCode) {
if (StringUtils.isEmpty(payCode)) {
return "payCode不能为空!.....";
}
// 1.查询数据库获取具体策略实现
PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
if (paymentChannel == null) {
return "没有查询支付渠道";
}
// 2.获取spring注入的bean的id
String strategyBeanId = paymentChannel.getStrategyBeanId();
if (StringUtils.isEmpty(strategyBeanId)) {
return "数据库没有配置strategyBeanId";
}
//3.通过spring上下文获取策略
PayStrategy payStrategy = SpringUtils.getBean(strategyBeanId, PayStrategy.class);
return payStrategy.toPayHtml();
}
}
10)控制层
import com.demo.context.PayContextStrategy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class PayController {
@Resource
private PayContextStrategy payContextStrategy;
/**
* 调用支付接口
*/
@GetMapping("/toPayHtml")
public String toPayHtml(String payCode) {
return payContextStrategy.toPayHtml(payCode);
}
}
10)测试
http://localhost:8080/toPayHtml?payCode=alipay
6.spring框架中哪些地方使用到了策略模式
new ClassPathXmlApplicationContext() 读取配置文件