01.策略模式

1.为什么要使用设计模式

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

2.什么是策略模式

将算法的责任和本身分割开,委派给不同的对象进行管理,最终解决多重if判断的问题

3.策略模式角色

1.环境角色:context上下文,客户端通过上下文获取具体的策略
2.抽象策略:定义共同行为方法的接口
3.具体策略:不同的策略不同的实现


4.通过枚举加工厂实现策略模式

链接:https://pan.baidu.com/s/1eDKSaH5njISprY3DMqMcuQ 
提取码:p29b 

 

1)pom依赖

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.11.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <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>
    </dependencies>

2)抽象策略

public interface PayStrategy {

    /**
     * 共同方法的行为
     * @return
     */
    String toPayHtml();
}

3)具体策略

import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;

@Component
public class AlipayStrategy implements PayStrategy {

    @Override
    public String toPayHtml() {
        return "调用支付宝接口...AliPayStrategy";
    }
}
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;

@Component
public class WeChatPayStrategy implements PayStrategy {

    public String toPayHtml() {
        return "调用微信支付接口...WeChatPayStrategy";
    }
}

4)工厂

import com.demo.enumeration.PayEnumStrategy;
import com.demo.strategy.PayStrategy;

public class StrategyFactory {

    /**
     * 通过工厂获取具体的策略
     */
    public static PayStrategy getPayStrategy(String strategyType) {
        try {
            String className = PayEnumStrategy.valueOf(strategyType).getClassName();
            PayStrategy payStrategy = (PayStrategy)Class.forName(className).newInstance();
            return payStrategy;
        } catch (Exception e) {
            return null;
        }
    }

}

5)枚举

public enum PayEnumStrategy {

    /**
     * 支付宝支付
     */
    ALI_PAY("com.demo.strategy.impl.AlipayStrategy"),
    /**
     * 微信支付
     */
    WECHAT_PAY("com.demo.strategy.impl.WeChatPayStrategy");

    PayEnumStrategy(String className) {
        this.setClassName(className);
    }

    private String className;

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }
}

6)环境角色上下文

import com.demo.factory.StrategyFactory;
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;

@Component
public class PayContextStrategy {

    /**
     * 通过上下文获取具体的策略
     */
    public String toPayHtml(String payCode) {
        PayStrategy payStrategy = StrategyFactory.getPayStrategy(payCode);
        if (payStrategy == null) {
            return "没有找到具体的实现策略";
        }
        return payStrategy.toPayHtml();
    }
}

7)控制层

import com.demo.context.PayContextStrategy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
public class PayController {

    @Resource
    private PayContextStrategy payContextStrategy;

    /**
     * 调用支付接口
     */
    @GetMapping("/toPayHtml")
    public String toPayHtml(String payCode) {
        return payContextStrategy.toPayHtml(payCode);
    }
}

8)启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

9)测试

http://localhost:8080/toPayHtml?payCode=ALI_PAY

5.通过数据库实现策略模式

链接:https://pan.baidu.com/s/1sHYlTzTL2CZOn3_5FYfruw 
提取码:bqjv 

 

1)数据库

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50727
 Source Host           : localhost:3306
 Source Schema         : design_pattern

 Target Server Type    : MySQL
 Target Server Version : 50727
 File Encoding         : 65001

 Date: 18/02/2022 16:49:34
*/

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,
  `channel_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `channel_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `strategy_bean_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of payment_channel
-- ----------------------------
INSERT INTO `payment_channel` VALUES (1, '支付宝支付', 'alipay', 'alipayStrategy');
INSERT INTO `payment_channel` VALUES (2, '微信支付', 'wechat', 'weChatPayStrategy');

SET FOREIGN_KEY_CHECKS = 1;

2)pom依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.11.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </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>
        <!-- mysql 依赖 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

3)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&serverTimezone=GMT%2B8
####打印MyBatias日志    
logging:
  level:
    ### 开发环境使用DEBUG 生产环境info或者error
    com.demo.mapper: DEBUG

4)渠道Entity

import lombok.Data;

@Data
public class PaymentChannelEntity {

    /**
     * ID
     */
    private Integer id;
    /**
     * 渠道名称
     */
    private String channelName;
    /**
     * 渠道ID
     */
    private String channelId;
    /**
     * 策略执行beanId
     */
    private String strategyBeanId;

}

5)渠道Mapper

import com.demo.entity.PaymentChannelEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@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}")
    PaymentChannelEntity getPaymentChannel(String payCode);
}

6)抽象策略

public interface PayStrategy {

    /**
     * 共同方法的行为
     * @return
     */
    String toPayHtml();
}

7)具体策略

import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;

@Component
public class AlipayStrategy implements PayStrategy {

    @Override
    public String toPayHtml() {
        return "调用支付宝接口...AliPayStrategy";
    }
}
import com.demo.strategy.PayStrategy;
import org.springframework.stereotype.Component;

@Component
public class WeChatPayStrategy implements PayStrategy {

    public String toPayHtml() {
        return "调用微信支付接口...WeChatPayStrategy";
    }
}

 8)spring上下文工具类

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

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

}

9)环境角色Context上下文

import com.demo.entity.PaymentChannelEntity;
import com.demo.mapper.PaymentChannelMapper;
import com.demo.strategy.PayStrategy;
import com.demo.utils.SpringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class PayContextStrategy {

    @Resource
    private PaymentChannelMapper paymentChannelMapper;

    /**
     * 通过上下文获取具体的策略
     */
    public String toPayHtml(String payCode) {
        if (StringUtils.isEmpty(payCode)) {
            return "payCode不能为空!.....";
        }
        // 1.查询数据库获取具体策略实现
        PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
        if (paymentChannel == null) {
            return "没有查询支付渠道";
        }

        // 2.获取spring注入的bean的id
        String strategyBeanId = paymentChannel.getStrategyBeanId();
        if (StringUtils.isEmpty(strategyBeanId)) {
            return "数据库没有配置strategyBeanId";
        }

        //3.通过spring上下文获取策略
        PayStrategy payStrategy = SpringUtils.getBean(strategyBeanId, PayStrategy.class);
        return payStrategy.toPayHtml();
    }
}

10)控制层 

import com.demo.context.PayContextStrategy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class PayController {

    @Resource
    private PayContextStrategy payContextStrategy;

    /**
     * 调用支付接口
     */
    @GetMapping("/toPayHtml")
    public String toPayHtml(String payCode) {
        return payContextStrategy.toPayHtml(payCode);
    }
}

 10)测试

http://localhost:8080/toPayHtml?payCode=alipay

6.spring框架中哪些地方使用到了策略模式

new ClassPathXmlApplicationContext()  读取配置文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值