扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
让我们看一下这个框架如何工作的具体实例吧。想象下面的用例:我们需要开发负责贷款申请的应用程序。我们需要满足下面的条件:
●检查应用的完整性否则驳回
●检查应用是否来自我们授权处理业务的应用。
●检查申请者的月收支比是否满足我们的要求。
●输入的申请通过我们不知道实现细节的持久服务被存储在数据库中,我们只知道他的接口(可能这个开发被外包到印度了)
●业务规则是可以改变的,这也是为什么需要规则引擎的设计了。
首先,设计一个表示贷款申请的类:
public class LoanApplication {
public static final String INVALID_STATE = "Sorry we are not doing business in your state";
public static final String INVALID_INCOME_EXPENSE_RATIO = "Sorry we cannot provide the loan given this expense/income ratio";
public static final String APPROVED = "Your application has been approved";
public static final String INSUFFICIENT_DATA = "You did not provide enough information on your application";
public static final String INPROGRESS = "in progress";
public static final String[] STATUSES =
new String[] {
INSUFFICIENT_DATA, INVALID_INCOME_EXPENSE_RATIO, INVALID_STATE, APPROVED, INPROGRESS
};
private String firstName;
private String lastName;
private double income;
private double expences;
private String stateCode;
private String status;
public void setStatus(String status) {
if(!Arrays.asList(STATUSES).contains(status))
throw new IllegalArgumentException("invalid status:" + status);
this.status = status;
}
// 其他getters and setters已被省略
}
我们使用的持久服务拥有如下接口:
public interface LoanApplicationPersistenceInterface {
public void recordApproval(LoanApplication application) throws Exception;
public void recordRejection(LoanApplication application) throws Exception;
public void recordIncomplete(LoanApplication application) throws Exception;
}
我们迅速开发一个什么也不做只是用来满足接口约定的MockLoanApplicationPersistence类来欺骗接口。
我们使用下面的SpringRuleEngine类的子类来加载Spring上下文并开始处理:
public class LoanProcessRuleEngine extends SpringRuleEngine {
public static final SpringRuleEngine getEngine(String name) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("SpringRuleEngineContext.xml");
return (SpringRuleEngine) context.getBean(name);
}
}
这时候,我们已经有了代码框架了,因此是时候写JUnit测试了,代码如下。其中包含一些假设:我们期望公司仅在两种州运作,德克萨斯和密歇根。而且我们只接受收支比在70%或更好的人的贷款申请。
public class SpringRuleEngineTest extends TestCase {
public void testSuccessfulFlow() throws Exception {
SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
LoanApplication application = new LoanApplication();
application.setFirstName("John");
application.setLastName("Doe");
application.setStateCode("TX");
application.setExpences(4500);
application.setIncome(7000);
engine.processRequest(application);
assertEquals(LoanApplication.APPROVED, application.getStatus());
}
public void testInvalidState() throws Exception {
SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
LoanApplication application = new LoanApplication();
application.setFirstName("John");
application.setLastName("Doe");
application.setStateCode("OK");
application.setExpences(4500);
application.setIncome(7000);
engine.processRequest(application);
assertEquals(LoanApplication.INVALID_STATE, application.getStatus());
}
public void testInvalidRatio() throws Exception {
SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
LoanApplication application = new LoanApplication();
application.setFirstName("John");
application.setLastName("Doe");
application.setStateCode("MI");
application.setIncome(7000);
application.setExpences(0.80 * 7000); //too high
engine.processRequest(application);
assertEquals(LoanApplication.INVALID_INCOME_EXPENSE_RATIO, application.getStatus());
}
public void testIncompleteApplication() throws Exception {
SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
LoanApplication application = new LoanApplication();
engine.processRequest(application);
assertEquals(LoanApplication.INSUFFICIENT_DATA, application.getStatus());
}
显然单元测试会失败因为我们还没有实现任何的逻辑。然而,随着项目的进展,越来越多的测试通过,最后JUnit测试就全部通过了。
让我们继续操作和规则的实现。我们希望操作与持久服务交互因此我们需要一个通用基类:
public abstract class AbstractPersistenceAwareAction extends AbstractAction {
private LoanApplicationPersistenceInterface persistenceService;
public void setPersistenceService(LoanApplicationPersistenceInterface persistenceService) {
this.persistenceService = persistenceService;
}
public LoanApplicationPersistenceInterface getPersistenceService() {
return persistenceService;
}
}
在我们的进程中第一个请求贷款申请的业务规则已经完成:
public class ValidApplicationRule extends AbstractRule {
protected boolean makeDecision(Object arg) throws Exception {
LoanApplication application = (LoanApplication) arg;
if(application.getExpences() == 0 ||
application.getFirstName() == null ||
application.getIncome() == 0 ||
application.getLastName() == null ||
application.getStateCode() == null) {
application.setStatus(LoanApplication.INSUFFICIENT_DATA);
return false;
}
return true;
}
}
注意这个类的一些有趣的现象:他是完全自包含的。他可以由自己实例化或者任何外部的应用容器,而类中的逻辑可以独立的开发和测试。这些现象使类成为基于规则应用的完美的程序块。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者