前言:设计模式源于生活
策略模式的基本概念
策略模式应用场景
策略模式优缺点
策略模式流程图
接下来我将通过三种方式实现策略模式
通用maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</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.18.12</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
通用工具类
@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);
}
}
基于静态内存模式,实现策略模式
定义抽象行为策略
public abstract class BehaviorStrategy {
/**
* 执行具体消息策略模式
*/
protected abstract void specificMsgStrategy ();
}
kafka消息渠道
@Slf4j
public class KafkaStrategy extends BehaviorStrategy {
@Override
protected void specificMsgStrategy() {
log.info("执行kafkaMQ消息模式发送消息");
}
}
rabbit消息渠道
@Slf4j
public class RabbitStrategy extends BehaviorStrategy {
@Override
protected void specificMsgStrategy() {
log.info("执行rabbitMQ消息模式发送消息");
}
}
rocket消息渠道
@Slf4j
public class RocketStrategy extends BehaviorStrategy {
@Override
protected void specificMsgStrategy() {
log.info("执行rocketMQ消息模式发送消息");
}
}
工厂模式类,用于维护对象的引用
public class FactoryStrategy {
/**
* 存储策略
*/
private static Map<String, BehaviorStrategy> stringBehaviorStrategyMap = new ConcurrentHashMap<>();
/**
* 初始化策略
*/
static {
stringBehaviorStrategyMap.put("kafka", new KafkaStrategy());
stringBehaviorStrategyMap.put("rabbit", new RabbitStrategy());
stringBehaviorStrategyMap.put("rocket", new RocketStrategy());
}
/**
* 执行具体策略
* @param strategyId
* @return
*/
public static BehaviorStrategy getStrategy(String strategyId) {
//待优化,如果查询空,友好提示
return stringBehaviorStrategyMap.get(strategyId);
}
}
测试类
public class Test {
public static void main(String[] args) {
BehaviorStrategy kafka = FactoryStrategy.getStrategy("kafka");
kafka.specificMsgStrategy();
}
}
效果图,选择策略是kafka模式,那么执行的业务逻辑就是kafka啦
基于工厂+spring容器实现策略模式
定义抽象行为策略
public abstract class BehaviorStrategy {
/**
* 执行具体消息策略模式
*/
public abstract void specificMsgStrategy ();
}
kafka消息渠道
@Slf4j
@Component
public class KafkaStrategy extends BehaviorStrategy {
@Override
public void specificMsgStrategy() {
log.info("执行kafkaMQ消息模式发送消息");
}
}
rabbit消息渠道
@Slf4j
@Component
public class RabbitStrategy extends BehaviorStrategy {
@Override
public void specificMsgStrategy() {
log.info("执行rabbitMQ消息模式发送消息");
}
}
rocket消息渠道
@Slf4j
@Component
public class RocketStrategy extends BehaviorStrategy {
@Override
public void specificMsgStrategy() {
log.info("执行rocketMQ消息模式发送消息");
}
}
工厂模式,通过将策略具体执行者,注入到容器中,工厂通过beanid到容器中执行不同的策略具体执行者,相比第一种就简单很多
@Component
public class FactoryStrategy {
public <T> T getStrategy(String strategyId,Class<T> t) {
if (StringUtils.isBlank(strategyId)) {
return null;
}
T bean = SpringUtils.getBean(strategyId, t);
return bean;
}
}
controller类
@RestController
public class StrategyController {
@Autowired
private FactoryStrategy factoryStrategy;
@GetMapping("/getStrategy")
public void getStrategy(@RequestParam("strategyId") String strategyId) {
BehaviorStrategy strategy = factoryStrategy.getStrategy(strategyId, BehaviorStrategy.class);
strategy.specificMsgStrategy();
}
}
效果图
基于spring+db+工厂实现策略模式
sql语句
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for strategy
-- ----------------------------
DROP TABLE IF EXISTS `strategy`;
CREATE TABLE `strategy` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`strategy_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '策略名称',
`strategy_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '策略ID',
`strategy_type` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '灵活-多种策略模式\r\n消息\r\n邮箱\r\n支付\r\n等等',
`strategy_bean_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '策略执行beanid',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '策略' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of strategy
-- ----------------------------
INSERT INTO `strategy` VALUES (1, 'kafka消息渠道', 'kafka', 'mq', 'kafkaDBStrategy');
INSERT INTO `strategy` VALUES (2, 'rabbitmq消息渠道', 'rabbit', 'mq', 'rabbitDBStrategy');
INSERT INTO `strategy` VALUES (3, 'rocketmq消息渠道', 'rouket', 'mq', 'rocketDBStrategy');
INSERT INTO `strategy` VALUES (4, '163邮箱渠道', '163', 'email', '163EmailStrategy');
SET FOREIGN_KEY_CHECKS = 1;
application.yml文件
###服务启动端口号
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/strategy?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
####打印MyBatias日志
logging:
level:
### 开发环境使用DEBUG 生产环境info或者error
com.xuyu.mapper: DEBUG
entity类
@Data
@TableName("strategy")
public class StrategyEntity {
@TableId
private Integer id;
@TableField("strategy_name")
private String strategyName;
@TableField("strategy_id")
private String strategyId;
@TableField("strategy_type")
private String strategyType;
@TableField("strategy_bean_id")
private String strategyBeanId;
}
定义抽象行为策略
public abstract class BehaviorStrategy {
/**
* 执行具体消息策略模式
*/
protected abstract void specificMsgStrategy ();
}
mapper类
@Repository
public interface StrategyMapper {
/**
* 根据策略id和类型查询不同的策略
*
* @param strategyId 策略id
* @param strategyType 策略类型
* @return
*/
@Select("SELECT id as id, strategy_name as strategyName, strategy_id as strategyId, strategy_type as strategyType, strategy_bean_id as strategyBeanId\n" +
"FROM strategy s WHERE s.strategy_id = #{strategyId} and strategy_type = #{strategyType}")
StrategyEntity getStrategyByStrategyId(@Param("strategyId") String strategyId, @Param("strategyType") String strategyType);
}
kafka消息渠道
@Component
@Slf4j
public class KafkaDBStrategy extends BehaviorStrategy {
@Override
public void specificMsgStrategy() {
log.info("执行kafkaMQ消息模式发送消息");
}
}
rabbit消息渠道
@Component
@Slf4j
public class RabbitDBStrategy extends BehaviorStrategy {
@Override
public void specificMsgStrategy() {
log.info("执行rabbitMQ消息模式发送消息");
}
}
rocket消息渠道
@Component
@Slf4j
public class RocketDBStrategy extends BehaviorStrategy {
@Override
public void specificMsgStrategy() {
log.info("执行rocketMQ消息模式发送消息");
}
}
工厂模式,通过将策略具体执行者,注入到容器中,工厂通过beanid到容器中执行不同的策略具体执行者,相比第一种就简单很多
@Component
public class FactoryDBStrategy {
@Autowired
private StrategyMapper strategyMapper;
public <T> T getStrategy(String strategyId, String type, Class<T> t) {
if (StringUtils.isBlank(strategyId)) {
return null;
}
if (StringUtils.isBlank(type)) {
return null;
}
StrategyEntity strategyEntity = strategyMapper.getStrategyByStrategyId(strategyId, type);
if (Objects.isNull(strategyEntity)) {
return null;
}
T bean = SpringUtils.getBean(strategyEntity.getStrategyBeanId(), t);
return bean;
}
}
controller类
@RestController
public class StrategyDBController {
@Autowired
private FactoryDBStrategy factoryDBStrategy;
@GetMapping("/getDBStrategy")
public void getStrategy(@RequestParam("strategyId") String strategyId, @RequestParam("strategyType") String strategyType) {
BehaviorStrategy strategy = factoryDBStrategy.getStrategy(strategyId, strategyType, BehaviorStrategy.class);
strategy.specificMsgStrategy();
}
}
效果图
到此策略模式就结束啦