经典设计模式之策略模式【如何重构聚合支付平台,对接【支付宝,微信,银联支付】】

写在前面:设计模式源于生活,而又高于生活!

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

使用设计模式可以重构整体架构代码、提高代码复用性、扩展性、减少代码冗余问题。

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判断问题。

版权@须臾之余https://my.oschina.net/u/3995125

策略模式架构图

策略模式环境搭建

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判断问题、提高扩展性、维护性增强、提高代码可读性。
缺点:后期维护不同策略类是非常多、定义类比较多、代码量增大。
优点大于缺点。

版权@须臾之余https://my.oschina.net/u/3995125

本文参考:蚂蚁课堂:http://www.mayikt.com

原文地址:https://www.cnblogs.com/xuyuzhiyu/p/11333946.html

时间: 2024-10-24 11:42:19

经典设计模式之策略模式【如何重构聚合支付平台,对接【支付宝,微信,银联支付】】的相关文章

[design-patterns]设计模式之一策略模式

设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不是那么容易做到了.现实世界的问题复杂多样,如何将显示问题映射到我们编写的程序中本就是困难重重.另一方面,软件开发中一个不变的真理就是"一切都在变化之中",这种变化可能来自于程序本身的复杂度,也可能来自于客户不断变化的需求,这就要求我们在编写程序中一定要考虑变化的因素,将变化的因素抽离出来,

前端也要学系列:设计模式之策略模式

做前端开发已经好几年了,对设计模式一直没有深入学习总结过.随着架构相关的工作越来越多,越来越能感觉到设计模式成为了我前进道路上的一个阻碍.所以从今天开始深入学习和总结经典的设计模式以及面向对象的几大原则. 今天第一天,首先来讲策略模式. 什么是策略模式? GoF四兄弟的经典<设计模式>中,对策略模式的定义如下: 定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换. 上边这句话,从字面来看很简单.但是如何在开发过程中去应用,仅凭一个定义依然是一头雾水.以笔者曾经做过的商户进销存系统为例

设计模式之策略模式(Strategy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

JavaScript设计模式之策略模式(学习笔记)

在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选择学习策略模式. 策略模式:定义了一系列家族算法,并对每一种算法单独封装起来,让算法之间可以相互替换,独立于使用算法的客户. 通常我并不会记得“牛顿第一定律”的具体内容,所以我也难保证我会对这个定义记得多久……用FE经常见到的东西来举个例子说明一下: $("div").animation(

Head First 设计模式之一 策略模式

策略模式 定义 策略模式定义了算法族,分别封装起来,让他们之间可以相互转换,此模式让算法的变化独立于使用算法的客户. 实例 上面的定义看起来说的不太清楚,记定义无意义,理解策略模式还是要看书中的鸭子例子.假设设计一个模拟鸭子的游戏,鸭子的种类有很多,有红头鸭.绿头鸭等等,鸭子可以划水,可以呱嘎叫.在这个模拟游戏的实现上,自然会想到用继承的方法,定义一个鸭子基类,具体的鸭子类型继承自鸭子基类.如下图所示 所有鸭子都会飞.呱呱叫和游泳,这些功能由基类来实现,display函数用来输出鸭子实例的类型,

大话设计模式_策略模式(Java代码)

策略模式:定义算法家族,分别封装,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户 简单描述:一个父类,多个子类实现具体方法.一个Context类持有父类的引用(使用子类实例化此引用),客户端代码只需要与此Context类交互即可 大话设计模式中的截图: 例子代码: 策略类: 1 package com.longsheng.strategy; 2 3 public abstract class Strategy { 4 5 public abstract double getR

设计模式之策略模式20170720

行为型设计模式之策略模式: 一.含义 策略模式是一种比较简单的模式,也叫做政策模式,其定义如下: 定义一组算法(可抽象出接口),将每个算法都封装起来,并且使它们之间可以互换(定义一个类实现封装与算法切换) 二.代码说明 1.主要有两个角色 1)Context封装角色 它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略,算法的直接访问,封装可能存在的变化. 2)策略角色 该类含有具体的算法 2.在用C实现过程中也是参考这种思想,以压缩,解压算法举例,具体实现如下: 1)策略模式使用场景

&lt;二&gt;读&lt;&lt;大话设计模式&gt;&gt;之策略模式

又和大家见面了,能够坚持写出第二篇文章真不错,好好加油. <<大话设计模式>>讲解策略模式是以商场收银软件程序开头的,那么问题来了,哪家商场收银软件强,开玩笑了.读过上篇文章<<简单工厂模式>>的知道,它有两个缺点:1.客户端依赖两个类,耦合性高:2.如果算法过多则需要写很多类.解决上面问题的就是策略模式了. 策略模式:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. 商场收银软件:单价*打折算法=售价.

设计模式之策略模式C++实现

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 策略模式UML图如下: 举例: 游泳池中有不同种类的鸭子,有绿头鸭,红头鸭,橡皮鸭,木头鸭等.不同鸭子的特征或行为不同.绿头鸭(MallardDuck)可以叫声是"quack",会飞:橡皮鸭叫声是"queak",不会飞:木头鸭不会叫,也不会飞.利用面向对象原理来设计来泳池中的各种鸭.要求:1.可扩展性好,当有新鸭加入时或鸭的行为有变动时,不用大量改动代码:2.复用性