设计模式之策略模式

 

为什么需要使用设计模式

使用策略模式进行对代码的优化,提高代码的复用性等

 

什么是策略模式

策略模式是对策略算法的包装,将不同的算法进行拆分开,委派给不同的对象管理,最终可以解决优化多重if判断问题

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

2.Strategy接口:定义一个Strategy接口。

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

定义策略接口->实现不同的策略类->利用多态或其他方式调用策略

为什么叫做策略模式

每个if判断都可以理解为就是一个策略。

策略模式优缺点

优点

算法可以自由切换(高层屏蔽算法,角色自由切换)

避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)

扩展性好(可自由添加取消算法 而不影响整个功能)

缺点

策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)

所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)

 

策略模式应用场景

聚合支付平台

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

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

 

策略模式架构

 

 

下边通过两种方式进行实现

①通过枚举类

②通过数据库查询

 

定义PayStrategy(抽象角色)

package com.liangzai.strategy;

/**
 * @author leiliang
 * @version 1.0
 * @Description 定义共同的借口
 * @date 2021/3/11 15:48
 */
public interface PayStrategy {
    public String toPayHtml();
}

 

ConcreteStrategy (具体实现策略类)

package com.liangzai.strategy.impl;

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

/**
 * @author leiliang
 * @version 1.0
 * @Description  支付宝具体的策略类
 * @date 2021/3/11 15:50
 */
@Component
public class AliPayStrategy implements PayStrategy {

    @Override
    public String toPayHtml() {
        return "支付宝支付。。。";
    }
}

 

package com.liangzai.strategy.impl;

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

/**
 * @author leiliang
 * @version 1.0
 * @Description  微信支付具体的策略类
 * @date 2021/3/11 15:50
 */
@Component
public class WechatPayStrategy implements PayStrategy {

    @Override
    public String toPayHtml() {
        return "微信支付。。。";
    }
}

 

PayContextService (上下文)

package com.liangzai.context;

import com.liangzai.entity.PaymentChannelEntity;
import com.liangzai.factory.StrategyFactory;
import com.liangzai.mapper.PaymentChannelMapper;
import com.liangzai.strategy.PayStrategy;
import com.liangzai.utils.SpringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author leiliang
 * @version 1.0
 * @Description 通过上下文获取具体的策略类
 * @date 2021/3/11 16:05
 */
@Component
public class PayContextStrategy {

    @Autowired
    PaymentChannelMapper paymentChannelMapper;

    /**
     * 枚举类的方式
     * @param payCode
     * @return
     */
    public String toPayHtml1(String payCode) {
        if (StringUtils.isEmpty(payCode)) {
            return "payCode 不能为空";
        }
        //使用策略工厂获取具体实现类   工厂进行初始化
        PayStrategy payStrategy = StrategyFactory.getPayStrategy(payCode);
        if (payStrategy == null) {
            return "没有找到具体策略实现";
        }
        return payStrategy.toPayHtml();
    }


    /**
     * 数据库的方式
     * @param payCode
     * @return
     */
    public String toPayHtml(String payCode) {
        if (StringUtils.isEmpty(payCode)) {
            return "payCode 不能为空";
        }
        //通过数据库方式获取
        PaymentChannelEntity channel = paymentChannelMapper.getPaymentChannel(payCode);
        if (channel == null) {
            return "没有查询到支付渠道";
        }
        //获取数据库中bean的id
        String channelId = channel.getStrategyBeanId();
        if (StringUtils.isEmpty(channelId)){
            return "没有查询到支付渠道策略类";
        }
        PayStrategy payStrategy = (PayStrategy) SpringUtils.getBean(channelId);
        return payStrategy.toPayHtml();
    }

}

 

SpringUtils

package com.liangzai.utils;

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

/**
 * Spring工具类
 */
@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);
    }

}

 

枚举

package com.liangzai.enums;

public enum PayEnumStrategy {

    /**
     *  支付宝支付
     */
    ALI_PAY("com.liangzai.strategy.impl.AliPayStrategy"),
    /**
     *  微信支付
     */
    WECHAT_PAY("com.liangzai.strategy.impl.WechatPayStrategy");
    PayEnumStrategy(String className) {
        this.setClassName(className);
    }

    public String getClassName() {
        return className;
    }

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

    /**
     * class完整地址
     */
    private String className;

}

 

StrategyFactory

package com.liangzai.factory;

import com.liangzai.enums.PayEnumStrategy;
import com.liangzai.strategy.PayStrategy;

/**
 * @author leiliang
 * @version 1.0
 * @Description 策略工厂 获取不同的策略实现类
 * @date 2021/3/11 15:59
 */
public class StrategyFactory {

    public static PayStrategy getPayStrategy(String strategyType) {
        try {
            //1.获取具体的策略实现类地址   通过反射机制获取类名
            String className = PayEnumStrategy.valueOf(strategyType).getClassName();
            return (PayStrategy) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return  null;
        }
    }
}

 

数据库访问层

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

 

-- ----------------------------

-- Records of payment_channel

-- ----------------------------

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

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

数据库访问层

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

}

 

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

 

 

 

Controller请求入口

package com.liangzai.controller;

import com.liangzai.context.PayContextStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author leiliang
 * @version 1.0
 * @Description
 * @date 2021/3/11 16:20
 */
@RestController
public class PayController {

    @Autowired
    PayContextStrategy payContextStrategy;

    @RequestMapping("/pay")
    public String toPayHtml(String payCode){
       return payContextStrategy.toPayHtml(payCode);
    }
}

 

执行流程:

枚举方式

paycontroller---->context上下文---->策略工厂通过反射获取类名------>执行PayStrategy接口

数据库方式

paycontroller---->context上下文---->获取数据库中bean的id通过spring.getBean获取类名------>执行PayStrategy接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值