目录
1.需求
今天在公司的业务功能中做到了公司的支付模块这块,支付这块相信大家应该都有一个比较清晰的概念。这里就先分享支付的相关功能,而是接着这个功能来引出一个比较基础的知识点,代码中分支控制。
在做支付功能的时候,别的什么也不用多想。我的第一印象就是好多种类型:阿里,微信,余额,银联等等这些是国内主流的支付方式,还有很多很少用到的支付方式,如果项目种有需求,也需要我们一个个来对接。如果牵扯到国外的项目,国外的支付方式也需要对接。所以支付这块是比较复杂的,所以考虑做成一个工具类,以便在后面继续进行迭代。这些都是后话。还是先说一说今天将要分享的分支控制。
在看到有这么多的分支时,第一反应就是if-else的分支结构或者switch case的结构,如下:
2. 传统方式
public void getPayType1(String payType, String orderId) {
if ("0".equals(payType)) {
//调用支付宝的支付方式
//do something
} else if ("1".equals(payType)) {
//调用微信的支付方式
//do something
} else if ("2".equals(payType)) {
//调用余额支付
//do something
} else if ("3".equals(payType)) {
//银联支付
//do something
} else {
//查询不到支付方式
}
}
public void getPayType2(String payType,String orderId) {
switch (payType) {
case "0":
//调用支付宝的支付方式
//do something
break;
case "1":
//调用支付宝的支付方式
//do something
break;
case "2":
//调用余额支付
//do something
break;
case "3":
//银联支付
//do something
break;
default:
//查询不到支付方式
break;
}
}
这两种结构的分支控制,优点的话,也就只能说大部分的人都会想到这么去写。
缺点就非常的突出了,我们单把支付宝和微信两种支付方式拿出来的说,各种初始参数的定义,以及各种支付参数的定义,就非常的多。两种支付方式糅合在一个类中,就会显得非常的杂乱。如果在加上银联或者后面不挺的迭代近的新的支付方式。整个类的结构就是非常的混乱的,不利用后期的维护,代码的可阅读性以及可扩展性就会比较差一些。
这种的分支结构时非常的不建议大家选择的。
在上面所说的这种结构的基础上,可能我们大家就会非常容易的过渡到下面所要所要说的结构。
3. 策略模式
策略模式:
比如说对象的某个行为,在不同场景中有不同的实现方式,这样就可以将这些实现方式定义成一组策略,每个实现类对应一个策略,在不同的场景就使用不同的实现类,并且可以*切换策略。
在网上找了张图,大家可以直观的看看:
然后我们再把策略模式带入到我们自己的业务中。就是把各种不同的支付方式抽取出来形成一个个的支付策略。然后再提供一个类似客户端的东西来选择不同的支付策略。这样的话,整个代码的逻辑就非常的清晰了,而且各种不同的支付方式也隔离开了,代码的可阅读性,以及后期的维护都会变得比较容易了。
/**
* @description: 支付策略的抽象类
* @author: WangYX
* @create: 2022-02-24 16:18
* @Version: 1.0.0
**/
public abstract class Strategy {
//不同的支付行为
public abstract void pay(String orderId);
}
/**
* @description: 阿里支付
* @author: WangYX
* @create: 2022-02-24 16:19
* @Version: 1.0.0
**/
public class AliPayStrategy extends Strategy {
@Override
public void pay(String orderId) {
//阿里支付
}
}
/**
* @description: 微信支付
* @author: WangYX
* @create: 2022-02-24 16:19
* @Version: 1.0.0
**/
public class WxPayStrategy extends Strategy {
@Override
public void pay(String orderId) {
//微信支付
}
}
/**
* @description: 余额支付
* @author: WangYX
* @create: 2022-02-24 16:19
* @Version: 1.0.0
**/
public class BalancePayStrategy extends Strategy {
@Override
public void pay(String orderId) {
//余额支付
}
}
/**
* @description:银联支付
* @author: WangYX
* @create: 2022-02-24 16:19
* @Version: 1.0.0
**/
public class UnionPayStrategy extends Strategy {
@Override
public void pay(String orderId) {
//银联支付
}
}
策略模式统一对外提供入口:
/**
* @description:
* @author: WangYX
* @create: 2022-02-24 16:27
* @Version: 1.0.0
**/
public class Context{
private Strategy strategy;
public PayClient(Strategy strategy) {
this.strategy = strategy;
}
public void pay(String orderId) {
this.strategy.pay(orderId);
}
}
以上整个策略模式基本完成,我们接下来来看看如何进行调用。
public void getPayType2(String payType,String orderId) {
switch (payType) {
case "0":
//调用支付宝的支付方式
new Context(new AliPayStrategy()).pay(orderId);
break;
case "1":
//调用微信的支付方式
new Context(new WxPayStrategy()).pay(orderId);
break;
case "2":
//调用余额支付
new Context(new BalancePayStrategy()).pay(orderId);
break;
case "3":
//银联支付
new Context(new UnionPayStrategy()).pay(orderId);
break;
default:
//查询不到支付方式
break;
}
}
以上便是整个策略模式的全部内容了,后面如果我们需要维护支付方式,只需要找到具体的类,修改类中的代码就好了。如果添加新的支付方式,只需继承Strategy类,然后把自己添加到switch的分支结构中。这个代码结构的逻辑脉络就比较清晰了。
我在项目中选用的就是这种结构。
但是,上面的方式还是存在着if-else的这中分支结构的选择。下面我们就在提供两外一种结构的选择。
4. 选择Map结构
- 采用Map结构
/**
* @description:
* @author: WangYX
* @create: 2022-02-24 15:48
* @Version: 1.0.0
**/
@Service
public class Pay3Service {
private Map<String, Strategy> payType = new HashMap<>();
@PostConstruct
public void init() {
payType.put("0", new AliPayStrategy());
payType.put("1", new WxPayStrategy());
payType.put("2", new BalancePayStrategy());
payType.put("3", new UnionPayStrategy());
}
public void getPayType2(String type,String orderId) {
Strategy strategy = payType.get(type);
strategy.pay(orderId);
}
}
采用Map的数据结构就完全规避了if-else的这种分支控制。
在其中我们初始化使用了@PostConstruct
这个注解,注解的作用就是在spring或者spring boot项目启动之后,初始化我们的map数据结构。
@PostConstruct注解好多人以为是Spring提供的。其实是Java自己的注解。
Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
通常我们会是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序:
Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
- 另外一种Map结构
/**
* @description:
* @author: WangYX
* @create: 2022-02-24 15:48
* @Version: 1.0.0
**/
@Service
public class Pay5Service {
private Map<String, Consumer<String>> payType = new HashMap<>();
@PostConstruct
public void init() {
payType.put("0", orderId -> new AliPayStrategy().pay(orderId));
payType.put("1", orderId -> new WxPayStrategy().pay(orderId));
payType.put("2", orderId -> new BalancePayStrategy().pay(orderId));
payType.put("3", orderId -> new UnionPayStrategy().pay(orderId));
}
public void getPayType2(String type, String orderId) {
Consumer<String> consumer = payType.get(type);
if (consumer != null) {
consumer.accept(orderId);
}
}
}
这种的方式,Map种的value是一种函数式接口,需要大家对函数式接口有基础的理解。
以上便是对if-else分支控制进阶方法的理解。