互联网架构-精讲设计模式-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:访问字节数组资源的实现类。

  1. new ClassPathXmlApplicationContext("");

  2. 进入该构造函数
    在这里插入图片描述

  3. 在这里插入图片描述

2. SpringBean初始化
在这里插入图片描述
SimpleInstantiationStrategy 简单初始化策略
CglibSubclassingInstantiationStrategy CGLIB初始化策略

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值