扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
业务逻辑通常与其他代码块紧密的混和在一起。当重量级的侵入式框架(如EJB)被使用时,区别业务逻辑与框架生成的代码就变得非常困难。
有一个软件需求在需求定义文档很难准确描述,却拥有使软件项目成功或失败的能力:适应性,这是用来衡量软件响应业务变更容易程度的标准。
现代企业要求响应快速及灵活,他们对企业软件也有同样的要求。可能你今天辛苦实现的业务规则在明天就被废弃了而且要求你根据变更快速而准确的改变。当你的包含业务逻辑的代码隐藏在大量其他代码中时,修改就变得缓慢、痛若且易出错了。
在今天的企业级软件中没有奇迹,比较流行的是规则引擎和各种业务过程管理(BPM)系统。如果你看一下市场上的宣传,这类工具都承诺一件事:保存在仓库中的捕获业务逻辑的圣杯能够清晰的分离且由自己维护,并随时准备让你现有的应用来调用。
虽然商业的规则引擎和BPM系统有许多优点,但也有不少缺点。最大的缺点就是价格,通常很容易就达到7位数。另一个就是除了主要的行业规范和众多记在纸上的标准外缺乏事实上的标准。而且随着越来越多的软件项目采用敏捷、轻量级的快速开发方法,这些重量级的工具变得不符合潮流了。
在这篇文章中,我们建立了一个简单的规则引擎,一方面平衡系统与业务逻辑的分离,另一方面由于他基于目前流行的强大的J2EE框架因而不需要承受商业软件的复杂性与不协调性。
J2EE世界中的Spring时代
在企业级软件的复杂性变得不能忍受及业务逻辑问题越来越重要时,Spring及类似的框架产生了。可以断定Spring在以后很长一段时间内是企业级Java中的佼佼者。Spring提供了很多工具及少量代码约定使J2EE的开发更面向对象,更容易也更有趣。
Spring的核心是IoC原则,这是一个奇特而超负荷的名字,但包含下面的简单想法:
●功能代码需要分开到更小的可管理片断
●这些片断是简单的,标准的JavaBean(简单的Java类拥有但不包含全部的JavaBean规范)
●你不需要参与管理这些Bean(如创建、销毁、设置依赖)
●相反Spring容器通过上下文定义来为你做这些(通常为XML文件格式)
Spring也提供了很多其他特性,如完整而强大的MVC框架,简便的JDBC开发包装及其他框架。但那些主题已经超出这篇幅文章的讨论范围。
在我描述需要什么来创建基于SPRING应用的简单规则引擎之前,让我们想一下为什么这是一种好的想法。
规则引擎设计有两点有趣的特性使其更有价值:
●首先,从应用领域分离了业务逻辑代码。
●其次,可配置性意味着业务规则的定义及其使用的顺序被存储在应用的外部,这样就可以由规则创建人员来控制而不是应用的使用者或者开发人员了。
Spring为规则引擎提供了一个好的方法。一个良好编码的Spring应用的强组件化的设计会使你的代码变成更小的、可管理的分散片断,这样就更易在Spring的上下文定义中配置。
继续了解在规则引擎设计的需求与Spring设计提供的功能之间的结合点。
基于Spring的规则引擎的设计
我们在Spring控制的JavaBean基础上开始设计,这里我们叫做规则引擎组件。我们来定义下面两种我们可能需要的组件类型:
●操作—在应用逻辑中确定用来做什么的组件
●规则—在一系列行为的逻辑流中做出决定的组件
我们都是面向对象设计的追随者,下面的基类建立了所有我们的组件需要通过参数被其他组件调用的基本功能:
public abstract class AbstractComponent {
public abstract void execute(Object arg) throws Exception;
}
当然基类是抽象的因为我们根本不需要这样的实例。
AbstractAction的代码扩展了基类来实现其他具体的操作:
public abstract class AbstractAction extends AbstractComponent {
private AbstractComponent nextStep;
public void execute(Object arg) throws Exception {
this.doExecute(arg);
if(nextStep != null)
nextStep.execute(arg);
}
protected abstract void doExecute(Object arg) throws Exception;
public void setNextStep(AbstractComponent nextStep) {
this.nextStep = nextStep;
}
public AbstractComponent getNextStep() {
return nextStep;
}
}
你可以看到,AbstractAction做两件事:首先他保存在规则引擎中被激活的下一个组件的定义;其次在他的execute()方法中,调用被具体类实现的doExecute()方法,在doExecute()返回后,如果存在下一个组件则调用他。
我们的AbstractRule也相当简单:
public abstract class AbstractRule extends AbstractComponent {
private AbstractComponent positiveOutcomeStep;
private AbstractComponent negativeOutcomeStep;
public void execute(Object arg) throws Exception {
boolean outcome = makeDecision(arg);
if(outcome)
positiveOutcomeStep.execute(arg);
else
negativeOutcomeStep.execute(arg);
}
protected abstract boolean makeDecision(Object arg) throws Exception;
// 为简单起见,positiveOutcomeStep和negativeOutcomeStep 的Getters 和 setters均已省略
在其execute()方法中,AbstractAction调用由子类实现的makeDecision()方法,然后根据方法的返回值,调用组件定义的肯定或否定结果的方法。
在我们介绍了SpringRuleEngine类后我们的设计就基本完成了:
public class SpringRuleEngine {
private AbstractComponent firstStep;
public void setFirstStep(AbstractComponent firstStep) {
this.firstStep = firstStep;
}
public void processRequest(Object arg) throws Exception {
firstStep.execute(arg);
}
}
这就是我们规则引擎主类的全部:定义第一个业务逻辑中的组件及开始执行的方法。
但是请稍等,在哪里绑定我们的类使之可以工作呢?下面你就可以看到如何利用Spring来帮助我们完成工作的方法了。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者