典型的策略模式,扣款有两种策略:固定扣款和自由扣款,比较简单,不多说,我们来看代码,先看抽象策略,也就是扣款接口,如代码清单35-3所示。
代码清单35-3 扣款策略接口
public interface IDeduction {
//扣款,提供交易和卡信息,进行扣款,并返回扣款是否成功
public boolean exec(Card card,Trade trade);
}
//扣款,提供交易和卡信息,进行扣款,并返回扣款是否成功
public boolean exec(Card card,Trade trade);
}
固定扣款的规则是固定金额和自由金额各扣除交易金额的一半,如代码清单35-4所示。
代码清单35-4 扣款策略一
public class SteadyDeduction implements IDeduction {
//固定性交易扣款
public boolean exec(Card card, Trade trade) {
//固定金额和自由金额各扣除50%
int halfMoney = (int)Math.rint(trade.getAmount() / 2.0);
card.setFreeMoney(card.getFreeMoney() - halfMoney);
card.setSteadyMoney(card.getSteadyMoney() - halfMoney);
return true;
}
}
//固定性交易扣款
public boolean exec(Card card, Trade trade) {
//固定金额和自由金额各扣除50%
int halfMoney = (int)Math.rint(trade.getAmount() / 2.0);
card.setFreeMoney(card.getFreeMoney() - halfMoney);
card.setSteadyMoney(card.getSteadyMoney() - halfMoney);
return true;
}
}
这个具体策略也非常简单,就是两个金额各自减去交易额的一半(注意除数是2.0,可不是2),然后再四舍五入,算法确实简单。该逻辑没有考虑账户余额不足的情况,也没有考虑异常情况,比如并发情况,读者可以想想看,一张卡有两笔消费同时发生时,是不是就发生错误了?一张卡同时有两笔消费会出现这种情况吗?会的,网络阻塞的情况,MQ多通道发送,在网络繁忙的情况下是有可能出现该问题,这里就不多介绍,有兴趣的读者可以看看MQ的资料。我们在这里的讲解实现的是一个快乐路径,认为所有的交易都是在安全可靠的环境中发生的,并且所有的系统环境都满足我们的要求。我们再来看另一个策略,更简单,如代码清单35-5所示。
代码清单35-5 扣款策略二
public class FreeDeduction implements IDeduction {
//自由扣款
public boolean exec(Card card, Trade trade) {
//直接从自由余额中扣除
card.setFreeMoney(card.getFreeMoney() - trade.getAmount());
return true;
}
}
//自由扣款
public boolean exec(Card card, Trade trade) {
//直接从自由余额中扣除
card.setFreeMoney(card.getFreeMoney() - trade.getAmount());
return true;
}
}
卡内的自由金额减去交易金额再修改卡内自由金额就完事了,异常情况不考虑。这两个具体的策略与我们的交易类型没有任何关系,也不应该有关系,策略模式就是提供两个可以相互替换的策略,至于在什么时候使用什么策略,则不是由策略模式来决定的。策略模式还有一个角色没出场,即封装角色,如代码清单35-6所示。
代码清单35-6 扣款策略的封装
public class DeductionContext {
//扣款策略
private IDeduction deduction = null;
//构造函数传递策略
public DeductionContext(IDeduction _deduction){
this.deduction = _deduction;
}
//执行扣款
public boolean exec(Card card,Trade trade){
return this.deduction.exec(card, trade);
}
}
//扣款策略
private IDeduction deduction = null;
//构造函数传递策略
public DeductionContext(IDeduction _deduction){
this.deduction = _deduction;
}
//执行扣款
public boolean exec(Card card,Trade trade){
return this.deduction.exec(card, trade);
}
}