java设计模式一一策略模式

1、什么是策略模式

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

  1. 环境(Constext)角色:持有一个strategy的引用
  2. 抽象策略(strategy)角色:只是一个抽象角色,通常有一个接口或抽象类实现。此角色给出所有的具体策略类所需要的的接口。
  3. 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

优点:策略模式最终帮助我们解决在实际开发中多重if判断问题、提高扩展性、维护性增强、提高代码可读性。
缺点:后期维护不同策略类是非常多、定义类比较多、代码量增大。

2、策略模式应用场景

比如搭建聚合支付平台的时候,这时候需要对接很多第三方支付接口,比如支付宝、微信支付、小米支付等。
通过传统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判断的问题。

3、策略模式架构图

在这里插入图片描述

4、策略模式环境搭建

4.1- maven依赖信息

 	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.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>

4.2- applicaton.yml

###服务启动端口号
server:
  port: 8081
spring:
  ###数据库相关连接
  datasource:
    url: jdbc:mysql://localhost:3306/design_pattern?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 246812gi
    driver-class-name: com.mysql.cj.jdbc.Driver
####打印MyBatias日志
logging:
  level:
    ### 开发环境使用DEBUG 生产环境info或者error
    com.redmaple.mapper: DEBUG

4.3- 实体类

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

}

4.4- 抽象角色(接口或抽象类)

public interface PayStrategy {
    /**
     * @description: 共同的算法实现骨架
     * @author: 若成风
     * @date: 2020/11/12 22:17
     * @return:
     */
    public String toPayHtml();
}

4.5- 具体实现角色

@Service
public class XiaoMiPayStrategy implements PayStrategy {
    /**
     * @description:
     * @author: 若成风
     * @date: 2020/11/12 22:22
     * @return: 
     */
    public String toPayHtml() {
        return "调用小米支付接口";
    }
}

@Service
public class AliPayStrategy implements PayStrategy {

    /**
     * @description:
     * @author: 若成风
     * @date: 2020/11/12 22:21
     * @return: 
     */
    @Override
    public String toPayHtml() {
        return "调用支付宝支付接口";
    }
}

4.6- 上下文调用

@RestController
public class PayContextController {

    @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.执行具体策略算法
        String pay = payStrategy.toPayHtml();
        System.out.println(pay);
        return pay;
    }

4.7- 工具类

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

5、数据库访问层

新建一个数据库 design_pattern 然后导入数据。

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 ('1', '支付宝渠道', 'ali_pay', 'aliPayStrategy');
INSERT INTO `payment_channel` VALUES ('2', '小米支付渠道', 'xiaomi_pay', 'xiaoMiPayStrategy');

6、测试

调用接口地址:localhost:8081/toPayHtml?payCode=xiaomi_pay
通过在数据库配置的payCode,解决多重if判断的问题。
github项目:java-design-pattern
【参考】:蚂蚁课堂菜鸟教程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值