状态机在线上录单系统的实际应用例子
来源:互联网 发布:练字软件免费下载 编辑:程序博客网 时间:2024/06/05 09:56
最近又碰到一个线上录单的系统。上一个是在3月份的时候,项目进度没调节好,需求也不停的变化,造成项目做的很累。
新的这个录单系统,经过考虑,打算使用状态机来创建服务器端应用框架,寄希望于可以将业务代码分离并很好的组织起来,简化开发和测试难度。
系统的目的是记录用户申请借款的请求。大概的流程,是线上录单的人员,将用户通过线下方式提交的请求通过web填入数据库中,然后提交借款资质审核机构,机构同意借款后,将借款申请包装成为一个产品,在线上出售。但是鉴于一些法务问题,在达成交易后,还需要将合同由录单人员交付第三方办理认证,并将认证提交资质审核机构存档。最后交易完成。(由于商业原因,没办法说明得太细)
整个过程,我这里的系统主要负责提供录单界面,记录申请单,调用接口资质审核机构,接受资质审核机构结果,等待产品出售完成消息,提供第三方认证上传界面,上传认证到资质审核机构。
于是,我制定了一个状态机接口,主要又有下方法:
public interface State{void create();void update();void submit();void invested();void certify();}然后,制作了一个抽象类,实现了这个接口:
public abstract class AbstractState {protected Request req;//真正要处理的请求;...public void create(){ throw new RuntimeException("Not suppoorted");}public void update(){... //( 和create等其他方法一样,都抛异常)}}
然后对于不同的状态,编写不同的子类来完成逻辑,例如对于初始状态StartState:
public class StartState extends AbstractState{@Resourceprivate RequestDAO reqDAO;@overridepublic void create(){ Request req = new Request(); reqDAO.insert(req); req.setStatus(NEW); super.factory.init(req);//切换一个新的状态}}
因为系统本身使用Spring作为容器,所以另一个问题是,如何将状态机和从数据库取出的DTO对象融合。在这里,我做了以下的工作:
首先创建了一个Spring管理的工厂类,负责创建State对象:
public class StateFactory implements ApplicationContextAware{ApplicationContextAware ctx;public State init(Request req){State state =null; switch(req.getStatus()){ case NEW: state = ctx.getBean("newState", NewState.class); case SUBMIT: state = ctx.getBean("submitState", SubmitState.class); ...//所有的状态机定义 }req.getState().setRequest(null);req.setState(state);}}
这里的req.getStatus()是申请单对象的状态属性,会存储在数据库中并取出。另外每个状态机实力是单例生成的,因为每个状态机对象要和一个业务对象对于,是有状态的。
于是在Service层,就可以这样方便的操作:
public class RequestService{ @Resource private RequestDAO reqDAO; @Resource private StateFactory factory; public void submit(Long reqId){ Request req = reqDAO.get(reqId); factory.init(req); req.getState().submit(); }}
于是,只要定义不同的实现状态,在状态中实现相应的方法,就可以完成相应的任务。相对而已,在不是用状态机时,我的代码中会看见许多状态判断的if...else...
public class RequestService{ public void submit(Long reqId){ Request req = reqDAO.get(reqId); if(req.getStatus()== NEW){ reqDAO.updateStatus(reqId, SUBMIT); //other stuff } } public void certify(Long reqId){ Request req = reqDAO.get(reqId): if(req.getStatus() == INVESTED){ RemoteService.syncCeriticate(req); reqDAO.updateStatus(reqId, CERTIFY); } }}而且,如果状态发生改变,这些分散的if...else都要全部分析,需要改的代码会很分散。比如要加一个提交第三方校验驳回的状态,就要找到所有可能相关的状态,挨个修改。另一个恐怖的事情就是状态事件捕获。比如要记录所有状态改变到数据库,或者对于特定的状态,发送短信通知用户。上述的实现,就要在每个方法都加入代码,侵入性极大,而且容易疏漏。但是状态机可以利用观察者模式,在状态机创建的时候,就将侦听接口植入,然后统一处理。 状态机的好处就在于,状态很集中,概念对应的业务也十分清晰。无论从编写和测试,都十分有效。
不过状态机也有局限,如果状态很少,而且也不太会发生改变,就不许要用了,框架不会为业务作出太多贡献,反而搞得累赘。另一个问题是,使用状态机的前提是,可以清楚的描述状态变迁,一般都是针对单一对象的判断。对于一些设计多对象的过程性的逻辑,个人更倾向于使用责任链。责任链相更灵活,但不象状态机那人“概念集中”——从另一个方面说,比起乱用状态机,乱用责任链更容易让人抓狂和莫名其妙:)
昨天在一个技术会议上听到一个同事说,做业务开发的不需要考虑设计模式什么的。我当时笑了笑,没说话。实际自己心里清楚,即使是这样看似很土,很基本的线上录单系统,巧做与否还是很重要的。更何况其他千奇百怪的需求。接下来的工作,我会设法将这个框架做成一个DSL(Domain Specific Language),最后做到能使用XML或者其他形式的文本定义状态机结构,将真正涉及到具体业务实现的步骤作为状态机的一部方,用极少的Java代码实现。
- 状态机在线上录单系统的实际应用例子
- 实际的状态机编程思想例子
- 实际的状态机编程思想例子(zz)
- 在线绘图插件--wPaint 的实际应用
- C#之Action的实际应用例子
- 最小二乘法实际应用的一个完整例子
- 字符串实际应用例子
- 状态机嵌套的例子
- 【CSS3】响应式布局的实际应用的小例子
- 状态机的应用
- 状态机跑飞的例子
- k-means算法实际应用的一个例子
- Java调用Webservice(asmx)的例子(实际应用)
- 串口状态机的应用[转载]
- Android 状态机stateMachine的应用
- 状态机在分布式系统中的应用
- Remoting 技术应用的实际项目 妇幼保健信息管理系统
- Game Programming with DirectX -- 11[粒子系统的实际应用]
- Ubuntu下安装JDK图文解析
- C++设计一个简单的壳(2)
- js判断当前窗口是否有父窗口
- uva 10740 - Not the Best(第k短路)
- Android平台下OpenGL初步
- 状态机在线上录单系统的实际应用例子
- 第三方库 EGOCache
- obj-c编程10:Foundation库中类的使用(6)[线程和操作队列]
- POJ 3723 Conscription(最大生成树)
- oracle查询
- 割点、割边和双连通分量
- Investment_多重背包!!!
- 【zz】c++编译,头文件使用问题
- 第二十一周工作日志