• 网站首页
  • 微服务
  • 设计模式
  • 并发编程
  • 源码分析
  • 中间件
  • 数据库
  • 文献
  • 工具
  • 其他
  • 设计模式之策略模式,实现重构聚合支付平台,对接支付宝、微信、银

    发布时间: 2019-12-19 17:09首页:架构技术精选 > 设计模式 > 阅读()

    为什么要使用设计模式重构代码

    使用设计模式可以重构整体架构代码、提高代码复用性、扩展性、减少代码冗余问题。Java高级工程师装逼的技能!  

    什么是策略模式

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

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

    策略模式应用场景

    比如搭建聚合支付平台的时候,这时候需要对接很多第三方支付接口,比如支付宝、微信支付、银联支付等。通过传统if代码判断的,后期的维护性非常差!

    public  String toPayHtml2(String payCode){
        if(payCode.equals("ali_pay")){
            return  "调用支付宝接口...";
        }
        if(payCode.equals("union_pay")){
            return  "调用银联支付接口";
        }
        if(payCode.equals("weChat_pay")){
            return  "调用微信支付接口...";
        }
        return  "未找到该接口...";
    }
    

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

    策略模式架构图

    策略模式环境搭建

    Maven依赖信息

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

    PayStrategy(抽象角色)

    /**
     * @title: PayStrategy  共同算法定义的骨架
     */
    public interface PayStrategy {
        /**
         *  策略模式共同算法的骨架
         */
        String toPayHtml();
    }

    ConcreteStrategy (具体实现角色)

    /**
     * @title: AliPayStrategy
     */
    @Component
    public class AliPayStrategy implements PayStrategy {
    
        @Override
        public String toPayHtml() {
            return "调用支付宝支付接口...";
        }
    }
    @Component
    public class UnionPayStrategy implements PayStrategy {
        @Override
        public String toPayHtml() {
            return "调用银联支付接口...";
        }
    }
    
    @Component
    public class WeChatPayStrategy implements PayStrategy {
        @Override
        public String toPayHtml() {
            return "调用微信支付接口";
        }
    }

    PayContextService (上下文)

    /**
     * @title: PayContextStrategy
     */
    @Component
    public class PayContextStrategy {
        @Autowired
        private PaymentChannelMapper paymentChannelMapper;
        @Autowired
        private SpringUtils springUtils;
    
        public String toPayHtml(String payCode){
            //1.使用payCode参数查询数据库获取beanid
            PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
            if(paymentChannel==null){
                return BaseReturnInfo.PAYMENTCHANNEL_IS_NULL;
            }
            //2.获取到beanid之后,使用spring容器获取实例对象
            String strategyBeanId = paymentChannel.getStrategyBeanId();
            if(StringUtils.isBlank(strategyBeanId)){
                return BaseReturnInfo.STRATEGYBEANID_IS_BLANK;
            }
            // 3.执行该实现的方法即可.... aliPayStrategy
            PayStrategy payStrategy = springUtils.getBean(strategyBeanId, PayStrategy.class);
            // 4.执行具体策略算法
            return payStrategy.toPayHtml();
        }
    }

    SpringUtils

    /**
     *  使用beanid 获取spring容器中的bean对象
     */
    @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);
        }
    
    }
    

     

    数据库访问层

    /*
     Navicat MySQL Data Transfer
    
     Source Server         : MySQL
     Source Server Type    : MySQL
     Source Server Version : 50720
     Source Host           : localhost:3306
     Source Schema         : design_pattern
    
     Target Server Type    : MySQL
     Target Server Version : 50720
     File Encoding         : 65001
    
     Date: 08/05/2019 09:20:48
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for payment_channel
    -- ----------------------------
    DROP TABLE IF EXISTS `payment_channel`;
    CREATE TABLE `payment_channel`  (
      `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
      `CHANNEL_NAME` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '渠道名称',
      `CHANNEL_ID` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '渠道ID',
      `strategy_bean_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '策略执行beanid',
      PRIMARY KEY (`ID`, `CHANNEL_ID`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '支付渠道 ' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of payment_channel
    -- ----------------------------
    INSERT INTO `payment_channel` VALUES (4, '支付宝渠道', 'ali_pay', 'aliPayStrategy');
    INSERT INTO `payment_channel` VALUES (5, '银联支付渠道', 'union_pay', 'unionPayStrategy');
    INSERT INTO `payment_channel` VALUES (6, '微信支付渠道', 'wechat_pay', 'weChatPayStrategy');
    
    SET FOREIGN_KEY_CHECKS = 1;
    

    数据库访问层

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

    Mapper层

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

    BaseReturnInfo 

    public interface BaseReturnInfo {
    
        String  PAYMENTCHANNEL_IS_NULL="没有该渠道信息";
    
        String STRATEGYBEANID_IS_BLANK="该渠道没有配置beanid";
    
        String PAYCODE_IS_BLANK="渠道code不能为空";
    }

    Controller层

    /**
     * @title: PayController
     */
    @RestController
    public class PayController {
        @Autowired
        private PayContextStrategy payContextStrategy;
    
        @RequestMapping("/toPayHtml")
        public  String toPayHtml(String payCode){
            if(StringUtils.isBlank(payCode)){
                return BaseReturnInfo.PAYCODE_IS_BLANK;
            }
            return payContextStrategy.toPayHtml(payCode);
        }
    }

    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=true
    ####打印MyBatias日志
    logging:
      level:
      ### 开发环境使用DEBUG 生产环境info或者error
       com.xuyu.mapper: DEBUG

    启动类

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

    效果



    优点:策略模式最终帮助我们解决在实际开发中多重if判断问题、提高扩展性、维护性增强、提高代码可读性。
    缺点:后期维护不同策略类是非常多、定义类比较多、代码量增大。
    优点大于缺点。
    特别声明:文章内容仅供参考,不造成任何投资建议。投资者据此操作,风险自担。

    网站首页 - 微服务 - 设计模式 - 并发编程 - 源码分析 - 中间件 - 数据库 - 文献 - 工具 - 其他

    本站不良内容举报联系客服QQ:483966038 官方微信:MYKT-xiaowei 服务热线:

    未经本站书面特别授权,请勿转载或建立镜像

    Copyright © 2016-2020 架构技术精选 版权所有 XMl地图