• (设计模式专题2)策略模式


    什么是策略模式

    策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重if判断问题。

    1.环境(Context)角色:持有一个Strategy的引用。

    2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

    3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

    定义策略接口->实现不同的策略类->利用多态或其他方式调用策略

    为什么叫做策略模式

    每个if判断都可以理解为就是一个策略。

    策略模式优缺点

    优点

    算法可以自由切换(高层屏蔽算法,角色自由切换)

    避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)

    扩展性好(可自由添加取消算法 而不影响整个功能)

    缺点

    策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)

    所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)

    策略模式应用场景 

    聚合支付平台

    比如搭建聚合支付平台的时候,这时候需要对接很多第三方支付接口,比如支付宝、微信支付、小米支付等。

    通过传统if代码判断的,后期的维护性非常差!

    Spring框架中使用的策略模式

    ClassPathXmlApplicationContext  Spring底层Resource接口采用策略模式

    Spring Resource 接口提供了如下实现类:

    UrlResource:访问网络资源的实现类。

    ClassPathResource:访问类加载路径里资源的实现类。

    FileSystemResource:访问文件系统里资源的实现类。

    ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:

    InputStreamResource:访问输入流资源的实现类。

    ByteArrayResource:访问字节数组资源的实现类。

    1new ClassPathXmlApplicationContext("");

    2.进入该构造函数。

     3.

    4.SpringBean初始化 SimpleInstantiationStrategy

    SimpleInstantiationStrategy  简单初始化策略

    CglibSubclassingInstantiationStrategy CGLIB初始化策略

    策略模式架构

    策略模式环境搭建

    创建项目名称 springboot_ strategy

    Maven依赖信息

     1 <parent>
     2     <groupId>org.springframework.boot</groupId>
     3     <artifactId>spring-boot-starter-parent</artifactId>
     4     <version>2.0.1.RELEASE</version>
     5 </parent>
     6 <dependencies>
     7     <!-- sprinboot web -->
     8     <dependency>
     9         <groupId>org.springframework.boot</groupId>
    10         <artifactId>spring-boot-starter-web</artifactId>
    11     </dependency>
    12     <dependency>
    13         <groupId>org.projectlombok</groupId>
    14         <artifactId>lombok</artifactId>
    15         <version>1.16.10</version>
    16     </dependency>
    17     <dependency>
    18         <groupId>commons-lang</groupId>
    19         <artifactId>commons-lang</artifactId>
    20         <version>2.6</version>
    21     </dependency>
    22     <dependency>
    23         <groupId>org.mybatis.spring.boot</groupId>
    24         <artifactId>mybatis-spring-boot-starter</artifactId>
    25         <version>1.1.1</version>
    26     </dependency>
    27     <!-- mysql 依赖 -->
    28     <dependency>
    29         <groupId>mysql</groupId>
    30         <artifactId>mysql-connector-java</artifactId>
    31     </dependency>
    32 </dependencies>

    PayStrategy(抽象角色)

    1 public interface PayStrategy {
    2 
    3     /**
    4      * 共同算法实现骨架
    5      * @return
    6      */
    7      public String toPayHtml();
    8 }

    ConcreteStrategy (具体实现角色)

    1 @Component
    2 public class AliPayStrategy  implements PayStrategy {
    3     public String toPayHtml() {
    4         return "调用支付宝支付接口";
    5     }
    6 }
    1 @Component
    2 public class XiaoMiPayStrategy implements PayStrategy {
    3     public String toPayHtml() {
    4         return "调用小米支付接口";
    5     }
    6 }

    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(工具类)

     1 @Component
     2 public class SpringUtils implements ApplicationContextAware {
     3 
     4     private static ApplicationContext applicationContext;
     5 
     6     @Override
     7     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
     8         this.applicationContext = applicationContext;
     9     }
    10 
    11     //获取applicationContext
    12     public static ApplicationContext getApplicationContext() {
    13         return applicationContext;
    14     }
    15 
    16     //通过name获取 Bean.
    17     public static Object getBean(String name){
    18         return getApplicationContext().getBean(name);
    19     }
    20 
    21     //通过class获取Bean.
    22     public static <T> T getBean(Class<T> clazz){
    23         return getApplicationContext().getBean(clazz);
    24     }
    25 
    26     //通过name,以及Clazz返回指定的Bean
    27     public static <T> T getBean(String name,Class<T> clazz){
    28         return getApplicationContext().getBean(name, clazz);
    29     }
    30 
    31 }

    枚举类

     1 public enum PayEnumStrategy {
     2 
     3     /**
     4      *  支付宝支付
     5      */
     6     ALI_PAY("com.mayikt.strategy.impl.AliPayStrategy"),
     7     /**
     8      *  银联支付
     9      */
    10     UNION_PAY("com.mayikt.strategy.impl.UnionPayStrategy");
    11     PayEnumStrategy(String className) {
    12         this.setClassName(className);
    13     }
    14 
    15     public String getClassName() {
    16         return className;
    17     }
    18 
    19     public void setClassName(String className) {
    20         this.className = className;
    21     }
    22 
    23     /**
    24      * class完整地址
    25      */
    26     private String className;
    27 
    28 }

    StrategyFactory

     1 public class StrategyFactory {
     2     public static PayStrategy getPayStrategy(String strategyType) {
     3         try {
     4             // 1.获取枚举中className
     5             String className = PayEnumStrategy.valueOf(strategyType).getClassName();
     6             // 2.使用java反射技术初始化类
     7             return (PayStrategy) Class.forName(className).newInstance();
     8         } catch (Exception e) {
     9             return null;
    10         }
    11     }
    12 }

    数据库访问层

    相关SQL语句:

     1 DROP TABLE IF EXISTS `payment_channel`;
     2 CREATE TABLE `payment_channel` (
     3   `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
     4   `CHANNEL_NAME` varchar(32) NOT NULL COMMENT '渠道名称',
     5   `CHANNEL_ID` varchar(32) NOT NULL COMMENT '渠道ID',
     6   `strategy_bean_id` varchar(255) DEFAULT NULL COMMENT '策略执行beanid',
     7   PRIMARY KEY (`ID`,`CHANNEL_ID`)
     8 ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='支付渠道 ';
     9 
    10 -- ----------------------------
    11 -- Records of payment_channel
    12 -- ----------------------------
    13 INSERT INTO `payment_channel` VALUES ('4', '支付宝渠道', 'ali_pay', 'aliPayStrategy');
    14 INSERT INTO `payment_channel` VALUES ('5', '小米支付渠道', 'xiaomi_pay', 'xiaoMiPayStrategy');

    实体类

     1 @Data
     2 public class PaymentChannelEntity {
     3    /** ID */
     4    private Integer id;
     5    /** 渠道名称 */
     6    private String channelName;
     7    /** 渠道ID */
     8    private String channelId;
     9    /**
    10     * 策略执行beanId
    11     */
    12    private String strategyBeanId;
    13 
    14 }

    数据库访问层

    1 public interface PaymentChannelMapper {
    2      @Select("
    " +
    3              "SELECT  id as id ,CHANNEL_NAME as CHANNELNAME ,CHANNEL_ID as CHANNELID,strategy_bean_id AS strategybeanid
    " +
    4              "FROM payment_channel where CHANNEL_ID=#{payCode}")
    5      public PaymentChannelEntity getPaymentChannel(String payCode);
    6 }

    优点:策略模式最终帮助我们解决在实际开发中多重if判断问题、提高扩展性、维护性增强、提高代码可读性。

    缺点:后期维护不同策略类是非常多、定义类比较多、代码量增大。

    优点大于缺点。

  • 相关阅读:
    Leetcode-2 两数相加
    离散数学-基本割集的找法
    Linux操作系统分析课程学习总结报告
    Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程
    Linux实验二:深入理解系统调用
    初始python
    水仙花数讲解
    Python-运算
    Python-列表
    Python-字符串
  • 原文地址:https://www.cnblogs.com/lmyupupblogs/p/12088237.html
Copyright © 2020-2023  润新知