蚂蚁课堂第5期-互联网架构-001:策略模式
001:策略模式
1 设计模式课程相关说明
为什么需要使用设计模式
使用设计模式可以重构整体架构代码、提高代码复用性、扩展性、减少代码冗余问题。
Java高级工程师必备的技能!
什么时候需要使用到设计模式重构呢?
实现代码重构的肯定是整体的骨架,如四期项目-聚合支付平台,写一些框架。
2 为什么需要使用策略模式
课程内容:
1、什么是策略模式?
2、什么场景使用策略模式
3、为什么命名为策略模式
4、上下文与策略模式关系
5、基于枚举+工厂实现策略模式
6、基于数据库方式实现策略模式
7、Spring框架中那些地方使用到策略模式
3 策略模式实现底层类图01
什么是策略模式
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重if判断问题。
1.环境(Context)角色:持有一个Strategy的引用。
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
定义策略接口->实现不同的策略类->利用多态或其他方式调用策略
为什么叫做策略模式
每个if判断都可以理解为就是一个策略。
4 策略模式实现底层类图02
5 基于枚举+工厂方式实现策略模式
Maven依赖信息 application.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&useSSL=false
####打印MyBatias日志
logging:
level:
### 开发环境使用DEBUG 生产环境info或者error
com.mayikt.member.mapper: DEBUG
PayStrategy(抽象角色)
public interface PayStrategy {
/**
* 共同方法的行为
* @return
*/
public String toPayHtml();
}
ConcreteStrategy (具体实现角色)
@Component
public class AliPayStrategy implements PayStrategy {
// <bean id=aliPayStrategy" class="com.mayikt.strategyPattern.strategy.impl.AliPayStrategy">
// 使用类名小写名称 从spring容器中获取具体策略对象
@Override
public String toPayHtml() {
return "调用支付宝接口 .. AliPayStrategy";
}
}
@Component
public class WeChatPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用微信接口 .. WeChatPayStrategy";
}
}
PayContextStrategy (上下文)
@Component
public class PayContextStrategy {
@Autowired
private PaymentChannelMapper paymentChannelMapper;
/**
* 获取具体策略的实现
*
* @param payCode
* @return
*/
public String toPayHtml(String payCode) {
if (StringUtils.isEmpty(payCode)) {
return "payCode不能为空..";
}
// 1.查询数据库获取具体策略实现
PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
if(paymentChannel == null){
return "没有查询到支付渠道";
}
// 获取spring注入的bean的id
String strategyBeanId = paymentChannel.getStrategyBeanId();
if(StringUtils.isEmpty(strategyBeanId)){
return "数据库没有配置strategyBeanId";
}
PayStrategy payStrategy = SpringUtils.getBean(strategyBeanId, PayStrategy.class);
/* // 使用策略工厂获取具体策略的实现
PayStrategy payStrategy = StrategyFactory.getPayStrategy(payCode);
if (payStrategy == null) {
return "没有找到具体策略的实现...";
}*/
return payStrategy.toPayHtml();
}
}
SpringUtils
@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 enum PayEnumStrategy {
/**
* 支付宝支付
*/
ALI_PAY("com.mayikt.strategyPattern.strategy.impl.AliPayStrategy"),
/**
* 微信支付
*/
WeChat_PAY("com.mayikt.strategyPattern.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 初始化bean
public class StrategyFactory {
// 使用策略工厂获取具体策略实现
public static PayStrategy getPayStrategy(String strategyType) {
// 1.获取具体的策略class地址
try {
String className = PayEnumStrategy.valueOf(strategyType).getClassName();
return (PayStrategy) Class.forName(className).newInstance();
}catch (Exception e){
return null;
}
}
}
6 使用Context上下获取具体策略
PayController
@RestController
public class PayController {
@Autowired
private PayContextStrategy payContextStrategy;
@RequestMapping("/toPayHtml")
public String toPayHtml(String payCode){
return payContextStrategy.toPayHtml(payCode);
}
}
策略模式优缺点
优点
算法可以*切换(高层屏蔽算法,角色*切换)
避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)
扩展性好(可*添加取消算法 而不影响整个功能)
缺点
策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)
7 基于数据库形式实现策略模式
相关SQL语句
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');
INSERT INTO `payment_channel` VALUES ('6', '微信支付渠道', 'wechat_pay', ' weChatPayStrategy');
数据库访问层
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);
}
PaymentChannelEntity
@Data
public class PaymentChannelEntity {
/** ID */
private Integer id;
/** 渠道名称 */
private String channelName;
/** 渠道ID */
private String channelId;
/**
* 策略执行beanId
*/
private String strategyBeanId;
}
8 Spring框架中那些地方使用策略模式
Spring框架中使用的策略模式
1. ClassPathXmlApplicationContext Spring底层Resource接口采用策略模式
new ClassPathXmlApplicationContext(“bean.xml”) 获取bean的资源
// 获取spring的资源: 文件形式、InputStream形式、ByteArray字节形式、网络来源
Spring 为 Resource 接口提供了如下实现类:
UrlResource:访问网络资源的实现类。
ClassPathResource:访问类加载路径里资源的实现类。
FileSystemResource:访问文件系统里资源的实现类。
ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:
InputStreamResource:访问输入流资源的实现类。
ByteArrayResource:访问字节数组资源的实现类。
-
new ClassPathXmlApplicationContext("");
-
进入该构造函数
2. SpringBean初始化
SimpleInstantiationStrategy 简单初始化策略
CglibSubclassingInstantiationStrategy CGLIB初始化策略