设计模式之策略模式(一)

第一、什么是策略模式

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

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

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

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

第二、策略模式应用场景

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

通过传统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判断问题。

第三、策略模式架构图

第四、策略模式案例

1、引入maven依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>
    <dependencies>
        <!-- sprinboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- mysql 依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

 2、创建一个接口PayStrategy(抽象角色)

/**
 * 抽象角色
 * 策略类
 */
public interface PayStrategy {
    /**
     * 共同算法实现骨架
     * @return
     */
    public String toPayHtml();
}

 3、创建具体实现类(AliPayStrategy)

/**
 * 支付子类
 */
@Component
public class AliPayStrategy implements PayStrategy {
    @Override
    public String toPayHtml() {
        return "调用支付接口";
    }
}

4、创建具体实现类(XiaoMiPayStrategy)

/**
 * 小米实现类
 */
@Component
public class XiaoMiPayStrategy implements PayStrategy {
    @Override
    public String toPayHtml() {
        return "调用小米接口";
    }
}

 5、创建一个得到bean对象的工具类(SpringContextUtil)

/**
 * 得到bean对象
 *
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    /**
     * 实现ApplicationContextAware接口的回调方法。设置上下文环境
     *
     * @param 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  <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public  <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}

6、创建一个实体类

@Data
public class PaymentChannelEntity {
    /** ID */
    private Integer id;
    /** 渠道名称 */
    private String channelName;
    /** 渠道ID */
    private String channelId;
    /**
     * 策略执行beanId
     */
    private String strategyBeanId;
}

 7、创建一个mapper接口

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

 8、创建一个上下文对象获取对应的实现类

/**
 * 上下文
 */
@Component
public class PayContextService {

    @Autowired
    private PaymentChannelMapper paymentChannelMapper;
    @Autowired
    private SpringContextUtil springContextUtil;

    public String toPayHtml(String payCode){
        //验证参数
        if(StringUtils.isBlank(payCode)){
            return "参数不能为空";
        }
        //使用该paycode查询
        PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
        if(paymentChannel==null){
            return  "该渠道为空...";
        }
        //获取对应的beanid
        String strategyBeanId = paymentChannel.getStrategyBeanId();
        if (strategyBeanId==null){
            return "beanId为空";
        }
        //得到对应的bean
        PayStrategy payStrategy = springContextUtil.getBean(strategyBeanId, PayStrategy.class);
        // 5.执行具体策略算法
        return payStrategy.toPayHtml();
    }
}

 9、创建一个controller层

@RestController
public class PayController {

    @Autowired
    private PayContextService payContextService;
    @RequestMapping("/index")
    public String index(String payCode){
        return payContextService.toPayHtml(payCode);
    }
}

 10、创建一个启动类

@SpringBootApplication
@MapperScan("com.yehui.mapper")
public class StartMainApp {
    public static void main(String[] args) {
        SpringApplication.run(StartMainApp.class);
    }
}

11、yml文件

spring:
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        password: root
        url: jdbc:mysql://localhost:3306/study
        username: root
logging:
  level:
    com.yehui.mapper: debug

 启动测试:

访问小米: http://localhost:8080/index?payCode=xiaomi_pay

效果

访问支付: http://localhost:8080/index?payCode=ali_pay

效果

 12、相关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='支付渠道 ';

INSERT INTO `payment_channel` VALUES ('4', '支付宝渠道', 'ali_pay', 'aliPayStrategy');

INSERT INTO `payment_channel` VALUES ('5', '小米支付渠道', 'xiaomi_pay', 'xiaoMiPayStrategy');

原文地址:https://www.cnblogs.com/cxyyh/p/10828994.html