public abstract class AbstractComponent {
public abstract void execute(Object arg) throws Exception;
}
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;
}
}
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;
public class SpringRuleEngine {
private AbstractComponent firstStep;
public void setFirstStep(AbstractComponent firstStep) {
this.firstStep = firstStep;
}
public void processRequest(Object arg) throws Exception {
firstStep.execute(arg);
}
}
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;
}
public class LoanProcessRuleEngine extends SpringRuleEngine {
public static final SpringRuleEngine getEngine(String name) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("SpringRuleEngineContext.xml");
return (SpringRuleEngine) context.getBean(name);
}
}
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());
}
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;
}
}
<!-- 規(guī)則引擎處理器 -->
<bean id="SharkysExpressLoansApplicationProcessor" class="SpringRuleEngine">
<property name="firstStep">
<ref bean="ValidApplicationRule"/>
</property>
</bean>
這個(gè)Bean簡(jiǎn)單地指明ValidApplicationRule為業(yè)務(wù)處理的第一個(gè)步驟。這個(gè)組件如下定義:
<!-- validation -->
<bean id="ValidApplicationRule" class="ValidApplicationRule">
<property name="positiveOutcomeStep">
<ref bean="ValidStateRule"/>
</property>
<property name="negativeOutcomeStep">
<ref bean="RejectionAction"></ref>
</property>
</bean>
public class ProcessRejectionAction extends AbstractPersistenceAwareAction {
protected void doExecute(Object arg) throws Exception {
LoanApplication application = (LoanApplication) arg;
if(LoanApplication.INSUFFICIENT_DATA.equals(application.getStatus()))
this.getPersistenceService().recordIncomplete(application);
else
this.getPersistenceService().recordRejection(application);
}
}
<!-- rejection -->
<bean id="RejectionAction" class="ProcessRejectionAction">
<property name="persistenceService">
<ref bean="LoanApplicationPersistenceService"/>
</property>
</bean>
<!-- persistence service -->
<bean id="LoanApplicationPersistenceService" class="MockLoanApplicationPersistence"/>
public class ValidStateRule extends AbstractRule {
private List validStates;
protected boolean makeDecision(Object arg) throws Exception {
LoanApplication application = (LoanApplication) arg;
if(validStates.contains(application.getStateCode())) {
return true;
}
application.setStatus(LoanApplication.INVALID_STATE);
return false;
}
public void setValidStates(List validStates) {
this.validStates = validStates;
}
}
<bean id="ValidStateRule" class="ValidStateRule">
<property name="validStates">
<list>
<value>TX</value>
<value>MI</value>
</list>
</property>
<property name="positiveOutcomeStep">
<ref bean="ValidIncomeExpenseRatioRule"/>
</property>
<property name="negativeOutcomeStep">
<ref bean="RejectionAction"></ref>
</property>
</bean>
聯(lián)系客服