什么是策略设计模式?
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重if判断问题。
1.环境(Context)角色:持有一个Strategy的引用。
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
策略模式应用场景:
根据不同的条件走不同的方法,无需返回或者返回相同类型的结果,常用于支付平台、文件解析(银行)等。
策略设计模式优点:
解决多重if判断问题,提高扩展性、维护性、可读性。在维护、扩展时只要增加相应代码并修改配置文件或者数据库即可。
策略设计模式缺点:
后期维护不同策略类是非常多、定义类比较多、代码量增大。
maven依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.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>
Strategy公共接口。
public interface PayStrategy { /** * 共同算法实现骨架 * @return */ public String toPayHtml(); }
ConcreteStrategy,封装了具体的算法或行为
@Component
|
@Component
|
PayContextService 上下文
@RestController
public class PayContextService {
@Autowired
private PaymentChannelMapper paymentChannelMapper;
@Autowired
private SpringUtils springUtils;
@RequestMapping("/toPayHtml")
public String toPayHtml(String payCode){
// 1.验证参数
if(StringUtils.isEmpty(payCode)){
return "payCode不能为空!";
}
// 2.使用PayCode查询
PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
if(paymentChannel==null){
return "该渠道为空...";
}
// 3.获取策略执行的beanid
String strategyBeanId = paymentChannel.getStrategyBeanId();
// 4.使用strategyBeanId获取对应spring容器bean信息
PayStrategy payStrategy = springUtils.getBean(strategyBeanId, PayStrategy.class);
// 5.执行具体策略算法
return payStrategy.toPayHtml();
}
}
SpringUtils spring容器获取bean
@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); } }
相关配置使用数据库维护,mysql建表语句:
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 class PaymentChannelEntity {
/** ID */
private Integer id;
/** 渠道名称 */
private String channelName;
/** 渠道ID */
private String channelId;
/**
* 策略执行beanId
*/
private String strategyBeanId;
}
public interface PaymentChannelMapper {
@Select("\n" +
"SELECT id as id ,CHANNEL_NAME as CHANNELNAME ,CHANNEL_ID as CHANNELID,strategy_bean_id AS strategybeanid\n" +
"FROM payment_channel where CHANNEL_ID=#{payCode}")
public PaymentChannelEntity getPaymentChannel(String payCode);
}