策略模式

什么是策略模式

哈喽,大家好,我是花臂,今天给大家讲一下策略模式的案列实战
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重if判断问题。

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

为啥要使用策略模式呢?给大家看一段代码:

public  String toPayHtml2(String payCode){
    if(payCode.equals("ali_pay")){
        return  "调用支付宝接口...";
    }
    if(payCode.equals("xiaomi_pay")){
        return  "调用小米支付接口";
    }
    if(payCode.equals("yinlian_pay")){
        return  "调用银联支付接口...";
    }
    return  "未找到该接口...";
}

可以看出这段代码非常冗余,而且不利于后期维护,而且给人一种很low的感觉,这个时候就需要用我们的策略模式来重构代码,ok,废话不多说,直接上代码。

具体代码实现

枚举实现策略模式

!pom文件

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

!抽象策略角色

public interface PayStrategic {
 //共同方法行为
 String toPayHtml();
}

!具体策略角色1

public class AliPay implements PayStrategic {
 @Override
 public String toPayHtml() {
  return "调用支付宝支付接口......";
 }
}

!具体策略角色2

public class WechatPay implements PayStrategic {
 @Override
 public String toPayHtml() {
  return "调用微信支付接口";
 }
}

!枚举类

//策略枚举类,所有策略的实现
public enum PayEnumStrategic {

 //支付宝支付
 ALI_PAY("com.zmq.strategic.impl.AliPay"),
 //微信支付
 WECHAT_PAY("com.zmq.strategic.impl.WechatPay");

 PayEnumStrategic(String className) {
  this.className = className;
 }

 //class完整路径
 private String className;

 public String getClassName() {
  return className;
 }

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

!策略工厂

//使用策略工厂获取具体的策略实现
@Component
public class StratePayFactroy {
 public static PayStrategic getPayStrategic(String payCode) throws Exception {

  try {
   //获取具体的class地址
   String className = PayEnumStrategic.valueOf(payCode).getClassName();
   return (PayStrategic) Class.forName(className).newInstance();
  } catch (Exception e) {
   return null;
  }
 }
}

!controller

@RestController
public class PayController {

 @Autowired
 private StratePayFactroy stratePayFactroy;

 //枚举实现策略模式
 @RequestMapping("toPay")
 public String toPay(String payCode) throws Exception {
  if (StringUtils.isEmpty(payCode)) {
   return "没有该支付方式";
  }
  PayStrategic payStrategic = stratePayFactroy.getPayStrategic(payCode);
  String s = payStrategic.toPayHtml();
  return s;
 }

测试一


这种方式是通过枚举的方式实现的策略模式,将class路径放在枚举中,然后通过前台传过来的payCode找到对应的class路径,然后通过反射Class.forname获取对象实现策略模式的,但是这种方式每次添加新的支付方式的话还是会很麻烦,要改枚举类,所以说这种方式不用。

数据库实现策略模式

建表

-- ----------------------------
-- 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) 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', 'aliPay');
INSERT INTO `payment_channel` VALUES ('5', '微信渠道', 'weichat_pay', 'wechatPay');

修改pom文件

原配置不变,新增依赖如下

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

修改具体策略角色

将所有的策略角色加入到spring容器中,加一个@Component注解

@Component
public class AliPay implements PayStrategic {
 @Override
 public String toPayHtml() {
  return "调用支付宝支付接口......";
 }
}
@Component
public class WechatPay implements PayStrategic {
 @Override
 public String toPayHtml() {
  return "调用微信支付接口";
 }
}

bean工具类

利用bean的id通过这个工具类将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);
    }

}

PayContext

@Component
public class PayContext {
 @Autowired
 private PaymentChannelMapper paymentChannelMapper;

 public String toPayHtml(String payCode) {
  if (StringUtils.isEmpty(payCode))
   return "payCode不能为空";
  PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
  if (paymentChannel == null){
   return "没有此种支付方式";
  }
  String strategyBeanId = paymentChannel.getStrategyBeanId();
  PayStrategic payStrategic =SpringUtils.getBean(strategyBeanId,PayStrategic.class);
  return payStrategic.toPayHtml();

 }

}

pojo

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

}

controller层

@RestController
public class PayController {

 @Autowired
 private PayContext payContext;

 //数据库实现策略模式
 @RequestMapping("toPay2")
 public String toPay2(String payCode) {
  return payContext.toPayHtml(payCode);

 }

}

测试二



这种方式就比那个枚举方式好多了,更加方便后期加维护,ok,本次教程就到这儿,有什么疑问欢迎下方评论区留言!

本文参考蚂蚁课堂

评论区



© [2020] · Powered by Typecho · Theme by Morecho
鄂ICP备20005123号