「一」Java设计模式,责任链模式的实际应用与思考
在之前的工作中,发现有些场景特别适合使用责任链模式,遂进行了一些研究,现记录一些心得。
责任链模式恰如其名:就像一根链条,将一个冗长的业务过程拆成一个个小业务,并将他们串联起来。在链条中,业务之间形成了一种“责任转移”的关系,即当A业务能处理的业务由A负责处理,A不能处理的则将责任转移到下一级负责。
由于一个很冗长的业务过程被拆分了一个个小业务,如此便带来了一些显而易见的优点:
- 扩展性:由于被拆分的小业务之间是互相独立的关系,所以在有业务变动需求时,不再需要在庞大的业务过程中谨慎的寻找需求加减的方式。只需要构建或移除“小业务”,并把它适时的“装配”或“移除”在责任链中,即可顺利完成业务的增减需求。
- 易读性:首先,“拆分”使得编码可以避免长方法(几十甚至几百行代码的方法)让代码变得冗长混乱难以理解。其次,“拆分”明确了链条上每个单位的责任划分,使每个【单位】的业务代码变得清晰明了。
举个例子:
在消费后,我们掏出手机付款,在使用支付软件支付时,可能会发生这样的场景:
支付软件默认使用了余额支付,但是发现钱不够,于是系统自动选择余额宝支付,可惜的是,余额宝的钱也不够。然后支付软件依次使用招商银行信用卡、招商银行储蓄卡、建设银行信用卡、建设银行储蓄卡、中国银行信用卡、中国银行储蓄卡……都试了一遍,发现里面的钱都不足以支付这笔账单。最后呢,支付软件发现你的理财中有可以灵活取用的部分可以直接用于扣款,滴,扣款成功了。
那么我们可以想象一下,支付软件在这种行为下的代码应该是怎样的?(ps:这里仅做业务演示便于理解,不代表实际编码方式)
public void pay(BigDecimal amount){
if(余额足够){
// 余额支付流程
}
if(余额宝足够){
// 余额宝支付流程
}
if(招行银行余额足够){
// 银行卡支付流程
}
if(某银行月足够){
// 某银行支付流程
}
...
if(基金余额足够){
// 基金支付流程
}
}
如上所示,在这个庞大的代码块中包含着大量平行且独立的业务,其中每个环节需要去判断每一种支付方式能否进行支付,能支付就去执行不同的支付流程。
从上边的代码中我们可以发现,这个方法中不仅因为包含大量的 if 判断而显得不那么优雅,也将大量业务代码全部“塞”进了同一个方法中。久而久之,随着业务扩展支付方式不断的增加或修改,这个方法会越来越大,代码也会变得越来越难以维护。
责任链模式就可以更优雅的实现上边的需求:
// 为责任链的每个节点统一父类
abstract class Pay {
// 每个节点下一个节点的对象
protected Pay intercept;
// 装配责任链中的下一个节点
public Pay next(Pay pay) {
this.intercept = pay;
return this.intercept;
}
// 最后一个节点,给予默认返回
public Pay end() {
return intercept = new Pay() {
@Override
public boolean doIntercept(BigDecimal amount) {
return false;
}
};
}
// 每个节点要实现的业务
public abstract boolean doIntercept(BigDecimal amount);
}
// 余额
class BalancePay extends Pay {
@Override
public boolean doIntercept(BigDecimal amount) {
System.out.println("余额扣款");
// 步骤1
// 步骤2
// ……
if (扣款失败) {
// 执行下一个支付方式
return intercept.doIntercept(amount);
}
return true;
}
}
// 余额宝
class BalanceBaoPay extends Pay {
@Override
public boolean doIntercept(BigDecimal amount) {
System.out.println("余额宝扣款");
// 步骤1
// 步骤2
// ……
if (扣款失败) {
return intercept.doIntercept(amount);
}
return true;
}
}
// 招商银行
class CMBPay extends Pay {
@Override
public boolean doIntercept(BigDecimal amount) {
System.out.println("招商银行扣款");
// 步骤1
// 步骤2
// ……
if (扣款失败) {
return intercept.doIntercept(amount);
}
return true;
}
}
我们首先建立一个基础的抽象类Pay,用于统一责任链上每个业务节点的规则。
然后再将实际的支付方式类继承Pay,实现doIntercept方法,并在doIntercept中实现该支付方式的实际业务逻辑。
接下来我们开始装配链并启动:
public static void main(String[] args) {
Pay pay = new BalancePay()
.next(new BalanceBaoPay())
.next(new CMBPay())
.end();
if (pay.doIntercept(BigDecimal.TEN)) {
// 扣款成功
System.out.println("success");
} else {
// 扣款失败
System.out.println("fail");
}
}
当支付成功时,直接返回true支付成功。当前业务节点支付失败时,使用 intercept.doIntercept 交给责任链的下一个节点去执行。
由于每个业务节点(支付方式)业务都是独立的,他们的组装也是自由的,我们可以随意增加或去除某个节点,也可以随意改变节点间的顺序。
责任链模式可以让我们特定情况下的代码变得优雅易于维护,但他也有相对的一些缺点。例如,构建责任需要创建大量对象,这很难避免会损失一部分性能,所以当需要构建的链条很长的话,就不推荐使用这种模式了。
最后呢,我想说在使用设计模式时,我们一定要注意不应当过度设计,为了设计模式而使用设计模式,如此倒是适得其反了。
对于责任链模式还有一些其他的实现方式,也能应对更多更丰富的场景,我想我会在接下来的文章中去总结其他的实现方式与场景。

浙公网安备 33010602011771号