欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

蚂蚁课堂第5期-互联网架构-001:策略模式

程序员文章站 2022-06-15 11:34:00
...

1 设计模式课程相关说明

为什么需要使用设计模式
使用设计模式可以重构整体架构代码、提高代码复用性、扩展性、减少代码冗余问题。
Java高级工程师必备的技能!

什么时候需要使用到设计模式重构呢?
实现代码重构的肯定是整体的骨架,如四期项目-聚合支付平台,写一些框架。

2 为什么需要使用策略模式

课程内容:
1、什么是策略模式?
2、什么场景使用策略模式
3、为什么命名为策略模式
4、上下文与策略模式关系
5、基于枚举+工厂实现策略模式
6、基于数据库方式实现策略模式
7、Spring框架中那些地方使用到策略模式

3 策略模式实现底层类图01

蚂蚁课堂第5期-互联网架构-001:策略模式
什么是策略模式
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重if判断问题

1.环境(Context)角色:持有一个Strategy的引用。
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
定义策略接口->实现不同的策略类->利用多态或其他方式调用策略

为什么叫做策略模式
每个if判断都可以理解为就是一个策略。

4 策略模式实现底层类图02

蚂蚁课堂第5期-互联网架构-001:策略模式

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);
    }
}

蚂蚁课堂第5期-互联网架构-001:策略模式
策略模式优缺点
优点
算法可以*切换(高层屏蔽算法,角色*切换)
避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)
扩展性好(可*添加取消算法 而不影响整个功能)
缺点
策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)

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:访问字节数组资源的实现类。

  1. new ClassPathXmlApplicationContext("");

  2. 进入该构造函数
    蚂蚁课堂第5期-互联网架构-001:策略模式

  3. 蚂蚁课堂第5期-互联网架构-001:策略模式

2. SpringBean初始化
蚂蚁课堂第5期-互联网架构-001:策略模式
SimpleInstantiationStrategy 简单初始化策略
CglibSubclassingInstantiationStrategy CGLIB初始化策略