使用Command与Factory模式消除业务代码中的if,else语句

3 篇文章 1 订阅

[2010-9-10]

    商业软件的一个特点就是拥有众多的业务逻辑,在进行一次操作时都会检查若干业务约束(如是否已登录等)。一般的方式就是采用 大量的if+else进行判断。

if (condition) {
    // do something
    return false;
} else if (condition) {
    // do something
    return false;
} else if ...
return true;


这样的问题在于,代码非常庞大,且难于理解,更不要谈复用了。这里我介绍一种采用Command与Factory模式的解决方案。

首先介绍一下我的设计,UML Class Diagram如下:

首先应该注意的是,每个业务约束(Constraint,以下简称C)都对应一个对应的处理(Handle,以下简称H),我把它们称为业务约束单元,所有业务约束单元共同构成了一个约束集 A={{C1,H1},{C2,H2}....},这样,对次对一个业务操作的限制判断使变成一个有序集的遍历过程,形象地说,就像一个pipeline,每个业务约束也就是里面的valve,只要一个valve失败,就不能达到终点 执行相应的业务操作,同时还要执行对应的H。因此,上面中你能看见名为“*pipeline”和“*valve”的类,它们就是对应的集与单元。

但是每种约束单元都有自己固有的C与H,需要进行动态方法调用,这里我使用了Command模式(实际上就是利用了OO的多态性), 在图中可以看见名为BizCrstValve的接口(Interface)与其下属的实现方式,也就是说,程序只管调用BizCrstValve里的canPass与doHandle方法,具体怎么实现,是由接口的实现类来确定的,程序要做的就是像 接口发送一个命令而已(就是为什么叫Command模式的原因)。这样,我们可以把所的valve都存在一个List里面,然后对其遍历,调用每个valve的canPass与doHandle命令,如果某一个valve的canPass返回 为false,则执行它的doHandle命令。

public Result perform() {
  for (BizCsrtValve valve : valves) {
   if (!valve.canPass(params)) {
    return valve.doHandle(params);
   }
  }
  return new Result(true);
}

随着valves的遍历,业务约束还在一个一个地查检,一但有一个业务逻辑失败,对应的操作就会激活。

这里再说一下BizCrstTypeEnum,由于我们已经将一个业务约束的C与其H封闭在一个valve中,那么它们完全就是高度可复用的了,因此, 可以给每个valve对应一杖举变量,这种我们就可以通过枚举变量来获得对应的valve了。如下:

BizCsrtTypeEnum.GOLD_USER_ONLY.getValve();

每个valve有自身的检测与处理机制,如下:

@Override
 public boolean canPass(Map<string, object=""> params) {
  try {
   int userID = (Integer) params.get(GoldUserOnlyValve.PARAM_USER_ID);
   if (userID == 12)
    return true;
   else
    return false;
  } catch (Exception e) {
   return false;
  }
 }
 @Override
 public Result doHandle(Map<string, object=""> params) {
  Result rs = new Result(false);
  rs.setBlockedValveType(BizCsrtTypeEnum.GOLD_USER_ONLY);
  
  return rs;
 }

在这里,枚举变量还有另外一个作用,那就是显示valve的错误信息,一个业务约束失败了我们总得给用户一个原因吧。

好了,现在还存在一个问题,那就是有线约束的H需要参数,而且,可能存在这么一种情况,那就是几个约束可能使用相同的参数, 如果每次都交给约束自己去生成的话,那岂不是太浪费了?明明可以复用的嘛。那我的方案就是在遍历所有valve前将所有valve需要的参数放入到一个map里面(你要调用你自己知道,你理所当然知道所有valve 需要哪些参数)。问题在于每个valve如何从map里面取出自己想要的参数?这里我认为,每个valve最了解自己需要什么参数,因此,每个valve有责任告诉调用着自己需要什么参数,正因为此,你才能在上面的 UML图里看见GoldUserOnlyValve这个类中存在一个PARAM_USER_ID的static变量,它表示这个valve需要一个名为user Id的变量,要使用“userID”来进行映射,如下

params.put(GoldUserOnlyValve.PARAM_USER_ID, 11);

在类图里还有一个名为Result的类,他的作用是存储一些valve失败时的信息,里面有个map,目前没有什么作用。

最后,总的流程如下:



现在,你再也不用写文章开头的那种代码了,只需要:

BizCsrtPipleline bp = new BizCsrtPipleline(params, BizCsrtTypeEnum.NEED_LOGIN.getValve(),
    BizCsrtTypeEnum.GOLD_USER_ONLY.getValve());
  Result result = bp.perform();


valve的添加顺序就是你的约束检测的顺序,现在是不是清爽了许多?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值