关于API的详细解释

关于Domain Model的讨论已经非常多了,炒炒冷饭,这里是自己的一些做法。 以Workitem(工作流里的工作项)作为例子 最开始的做法: 一个实体类叫做Workitem,指的是一个工作项或者称为任务项 一个DAO类叫做WorkitemDao 一个业务逻辑类叫做WorkitemManager(或者叫做WorkitemService) 主要看看WorkitemManager,因为主要逻辑集中在这里  

public   class  WorkitemManager {          private  WorkItemDAO workItemDAO;      public   void  setWorkItemDAO(WorkItemDAO workItemDAO) {          this .workItemDAO  =  workItemDAO;     }           /**      * 提交工作项      *  @param  workitemId 工作项ID       */      public   void  commitWorkitem(String workitemId){             WorkItem workitem  =  workItemDAO.getWorkItem(workitemId);              // 当前工作项结束         workitem.complete();          int  sID  =  workitem.getSequenceId();          // 找到所对应的节点         InstActivity instActivity = workitem.getInstActivity();          // 查找是否存在下一工作项         WorkItem sequenceWorkitem  =  workItemDAO.findSequenceWorkItem(instActivity.getId(), sID  +   1 );          // 如果不存在则触发节点流转          if  (sequenceWorkitem  ==   null ) {             instActivity.signal();         }          // 否则把下一工作项激活          else  {             sequenceWorkitem.setExecutive();         }     }      }

Workitem类里有一些状态转换的逻辑,这样避免直接调用get/set属性方法  

public   class  Workitem{          private   int  state  =  WorkitemInfo.PREPARE;          /**      * 委派工作项       */      public   void  commission() {          if  (state  !=  WorkitemInfo.EXECUTE  &&  state  !=  WorkitemInfo.SIGNINED                  &&  state  !=  WorkitemInfo.TOREAD &&  state  !=  WorkitemInfo.SUSPEND)              throw   new  WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);         setState(WorkitemInfo.COMMISSIONED);         setCommitted( new  Timestamp(System.currentTimeMillis()));     }      /**      * 完成工作项       */      public   void  complete() {          if  (state  !=  WorkitemInfo.SIGNINED)              throw   new  WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);         setState(WorkitemInfo.COMPLETE);         setCompleted( new  Timestamp(System.currentTimeMillis()));     } }

接下来的做法: 三个类不变,将WorkitemManager打平,将逻辑移动到Workitem  

public   class  WorkitemManager {          private  WorkItemDAO workItemDAO;      public   void  setWorkItemDAO(WorkItemDAO workItemDAO) {          this .workItemDAO  =  workItemDAO;     }           /**      * 提交工作项      *  @param  workitemId 工作项ID       */      public   void  commitWorkitem(String workitemId){             WorkItem workitem  =  workItemDAO.getWorkItem(workitemId);              // 当前工作项提交         workitem.commit();     }      }

实际上此时WorkitemManager的功能非常有限,仅仅是事务边界和获取workitem对象,甚至在一些情况下可以省略。 通过一个Container类将spring的applicationContext进行封装,然后通过getBean()的静态方法即可访问被spring所管理的bean。实际是将workItemDAO隐式注入了Workitem。  

public   class  Workitem{          /**      * 提交工作项       */      public   void  commit() {          if  (state  !=  WorkitemInfo.EXECUTE  &&  state  !=  WorkitemInfo.SIGNINED                  &&  state  !=  WorkitemInfo.TOREAD &&  state  !=  WorkitemInfo.SUSPEND)              throw   new  WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);         setState(WorkitemInfo.COMMISSIONED);         setCommitted( new  Timestamp(System.currentTimeMillis()));          int  sID  =  workitem.getSequenceId();         WorkItemDAO workItemDAO = (WorkItemDAO)Container.getBean( " workItemDAO " );          // 查找是否存在下一工作项         WorkItem sequenceWorkitem  =  workItemDAO.findSequenceWorkItem(instActivity.getId(), sID  +   1 );          // 如果不存在则触发节点流转          if  (sequenceWorkitem  ==   null ) {             instActivity.signal();         }          // 否则把下一工作项激活          else  {             sequenceWorkitem.setExecutive();         }     } }

这样带来的好处是业务逻辑全部被封装到Domain Model,Domain Model之间的交互变得非常的简单,没有频繁的set/get,直接调用有业务语义的Domain Model的方法即可。问题在于单元测试时脱离不了spring的容器,workItemDAO需要stub。我觉得这个问题不大,问题是Domain Model开始变得臃肿,在业务逻辑复杂时代码行急剧膨胀。 现在的做法 以上三个类保持不变,增加一个类WorkitemExecutor,将业务逻辑移步。  

public   class  Workitem{          /**      * 提交工作项       */      public   void  commit() {          if  (state  !=  WorkitemInfo.EXECUTE  &&  state  !=  WorkitemInfo.SIGNINED                  &&  state  !=  WorkitemInfo.TOREAD &&  state  !=  WorkitemInfo.SUSPEND)              throw   new  WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);         setState(WorkitemInfo.COMMISSIONED);         setCommitted( new  Timestamp(System.currentTimeMillis()));         WorkitemExecutor workitemExecutor = (WorkitemExecutor)Container.getBean( " workitemExecutor " );         workitemExecutor.commitWorkitem( this );     } } public   class  WorkitemExecutor {          private  WorkItemDAO workItemDAO;      public   void  setWorkItemDAO(WorkItemDAO workItemDAO) {          this .workItemDAO  =  workItemDAO;     }           /**      * 提交工作项      *  @param  workitemId 工作项ID       */      public   void  commitWorkitem(Workitem workitem){          int  sID  =  workitem.getSequenceId();          // 找到所对应的节点         InstActivity instActivity = workitem.getInstActivity();          // 查找是否存在下一工作项         WorkItem sequenceWorkitem  =  workItemDAO.findSequenceWorkItem(instActivity.getId(), sID  +   1 );          // 如果不存在则触发节点流转          if  (sequenceWorkitem  ==   null ) {             instActivity.signal();         }          // 否则把下一工作项激活          else  {             sequenceWorkitem.setExecutive();         }     }      }

将业务逻辑拆分成两部分,一部分在Workitem,另一部分委托给WorkitemExecutor。实际上是Domain Model将复杂逻辑的情况重新外包出去。调用的时候,面向的接口还是Domain Model的方法。注意到WorkitemExecutor和WorkitemManager的API是非常相似的。实际可以这样认为,传统的方式 Client->(Business Facade)->service(Business Logic 部分依赖Domain Model)->Data Access(DAO)。 现在的方式 Client->(Business Facade)->Domain Model->service->Data Access(DAO)。 另外,在返回client端的查询的时候还是倾向于直接调用DAO,而不是通过Domain Model。 http://www.blogjava.net/ronghao 荣浩原创,转载请注明出处:)  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值