Part1_精讲设计模式_策略模式

                                         Part 1 精讲设计模式

                                                                                        1.2 策略模式               

                                                                                                                                                                                        田超凡

                                                                                                                                                                         2019年10月22日

1.策略模式

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

策略模式是一种行为型模式,主要针对代码运行时的行为进行规范,提高可扩展性、可维护性和代码可读性。

 

2.策略模式架构图

Part1_精讲设计模式_策略模式_第1张图片

 

环境角色(Context):管理所有抽象策略角色,持有抽象策略角色Strategy的引用

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

具体策略角色(ConcreteStrategy):包装了相关的算法或行为,继承/实现抽象策略角色(抽象类/接口)定义的行为规范

3.策略模式应用场景

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

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

public  String toPayHtml2(String payCode){
    if(payCode.equals("ali_pay")){
        return  "调用支付宝接口...";
    }
    if(payCode.equals("xiaomi_pay")){
        return  "调用小米支付接口";
    }
    if(payCode.equals("yinlian_pay")){
        return  "调用银联支付接口...";
    }
    return  "未找到该接口...";
}

 

这时候可以通过策略模式解决多重if判断问题。

4.策略模式实现-环境搭建

创建项目名称 springboot_strategy

Maven依赖信息

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.0.1.RELEASEversion>
parent>
<dependencies>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>1.16.10version>
    dependency>
    <dependency>
        <groupId>commons-langgroupId>
        <artifactId>commons-langartifactId>
        <version>2.6version>
    dependency>
    <dependency>
        <groupId>org.mybatis.spring.bootgroupId>
        <artifactId>mybatis-spring-boot-starterartifactId>
        <version>1.1.1version>
    dependency>
    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
    dependency>
dependencies>

 

 

PayStrategy(抽象角色)

public interface PayStrategy {

    /**
     * 共同算法实现骨架
     * @return
     */
     public String toPayHtml();
}

 

 

ConcreteStrategy (具体实现角色)

@Component
public class AliPayStrategy  implements PayStrategy {
    public String toPayHtml() {
        return "调用支付宝支付接口";
    }
}

 

 

@Component
public class XiaoMiPayStrategy implements PayStrategy {
    public String toPayHtml() {
        return "调用小米支付接口";
    }
}

 

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上下文环境ApplicationContext工具类)

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

}

 

 

可选数据库访问层

相关SQL语句

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

 

 

 

5.策略模式小结

窍门:关于策略模式数据载体,如果不想访问数据库,可以定义枚举和常量存在运行时的内存中,一样可以通过具体的支付方式策略角色执行对应的方法。

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

缺点:本案例只是一个支付类型的策略模式案例,在真实环境中如果后期策略模式类型很多,就会导致需要新建各种类型的抽象策略角色及对应的具体策略实现角色, 导致后期定义类比较多、代码量增大

总体而言,策略模式的优点(可扩展性、可维护性、代码可读性)大于缺点(代码量增大),是一种比较常用的行为型设计模式。

 

转载请注明原作者

 

你可能感兴趣的:(Java架构)