设计模式 (一) | 策略模式

Scroll Down

前言

先来思考几个问题:策略模式用在哪里,怎么使用,思想是什么
本次来一点实际开发中会用到的小技巧。
比如平时大家是否都会写类似这样的代码

if (a) {
	// 微信支付
} else if(b) {
	// 阿里支付
} else if(c) {
	// 银联支付
}

试想而知,条件少还好,一旦 elseif 过多这里的逻辑将会比较混乱,并很容易出错。所以就有了我们今天要讲的设计模式--策略模式

刚开始条件较少,也就没管那么多直接写的,这次终于忍无可忍就把他重构了,重构之后这里的结构如下:

 String className = PayEnumStrategy.valueOf(strategyType).getClassName();
      return (PayStrategy) Class.forName(className).newInstance();

实现思路草图

image.png
** 整体思路如下:**

1、定义一个 InnerCommand 接口,其中有一个 process 函数交给具体的业务实现。
2、根据自己的业务,会有多个类实现 InnerCommand 接口;这些实现类都会注册到 SpringBean 容器中供之后使用。
3、通过客户端输入命令,从 SpringBean 容器中获取一个 InnerCommand 实例。
4、执行最终的 process 函数。

话不多说,那我们就干起来,我现在使用枚举Enum来实现的,也可以用mysql实现。
代码撸起来

一、准备工作--引入依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

二、准备工作--枚举

public enum PayEnumStrategy {
    ALI_PAY("com.qw.boot.strategy.service.impl.AliPayStrategy"),
    WECHAT_PAY("com.qw.boot.strategy.service.impl.WeChatPayStrategy");
    private String className;
    PayEnumStrategy(String className) {
        this.setClassName(className);
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
}

三、逻辑接口 PayStrategy.java

public interface PayStrategy {

    String toPayHtml();

}

四、每段逻辑的实现 WeChatPayStrategy.java 和 AliPayStrategy.java

@Service
public class WeChatPayStrategy implements PayStrategy {
    @Override
    public String toPayHtml() {
        return "调微信接口!!!WxPayStrategy";
    }
}

@Service
public class AliPayStrategy implements PayStrategy {
    @Override
    public String toPayHtml() {
        return "调用阿里支付宝接口!!!AliPayStrategy";
    }
}

五、核心获取上下文。StrategyFactory.java

public class StrategyFactory {
    public static PayStrategy getPayEnumStrategy(String strategyType) {
        try{
            String className = PayEnumStrategy.valueOf(strategyType).getClassName();
            return (PayStrategy) Class.forName(className).newInstance();
        } catch (Exception e){
           e.printStackTrace();
           return null;
        }
    }
}

六、接口测试 TestController.java

@Controller
@RequestMapping("test")
public class TestController {

    @Autowired
    private PayContextStrategy payContextStrategy;

    @RequestMapping("toPayHtml")
    public String toPayHtml(String payCode){
        String ret = payContextStrategy.toPayHtml(payCode);
        return ret;
    }
}

七、最后我们来一个根据code获取哪一个策略的判断

@Component
public class PayContextStrategy {
    public String toPayHtml(String payCode) {
        if (StringUtils.isEmpty(payCode)) {
            return "payCode不可为空";
        }
        PayStrategy payStrategy = StrategyFactory.getPayEnumStrategy(payCode);
        if (payStrategy == null){
            return "没有找到具体的实现";
        }
        return payStrategy.toPayHtml();
    }
}

这样就大功告成了!!!

尾声:我们来回顾前面几个问题?

1、策略模式用在哪里,怎么使用,思想是什么
1、策略模式一般用在有很多种方式处理,但前面是一样的行为,比如if很多来判断实行每一个策略
2、怎么使用:定义多个实现方法,来实现同一个接口,这也就是不同的策略,再来根据枚举来对应实现每一个策略
3、思想就是:根据class类型获取注册到spring中的处理器上下文

总结:

利用策略模式可以简化繁杂的if else代码,方便维护,而利用自定义注解和自注册的方式,可以方便应对需求的变更。本文只是提供一个大致的思路,还有很多细节可以灵活变化,例如使用枚举类型、或者静态常量,作为支付的类型,相信你能想到更多更好的方法。