从贫血到充血Domain Model
来源:互联网 发布:圣剑英雄传源码 编辑:程序博客网 时间:2024/04/20 12:01
关于Domain Model的讨论已经非常多了,炒炒冷饭,这里是自己的一些做法。以Workitem(工作流里的工作项)作为例子最开始的做法:一个实体类叫做Workitem,指的是一个工作项或者称为任务项一个DAO类叫做WorkitemDao一个业务逻辑类叫做WorkitemManager(或者叫做WorkitemService)主要看看WorkitemManager,因为主要逻辑集中在这里
现在的做法以上三个类保持不变,增加一个类WorkitemExecutor,将业务逻辑移步。
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。
- 从贫血到充血Domain Model
- 从贫血到充血Domain Model
- JAVA 贫血的 Domain Model 的心得
- 贫血模型和充血模型
- 贫血模型与充血模型
- 贫血模型和充血模型
- 贫血模型和充血模型
- 贫血对象和充血对象
- 贫血模型和充血模型
- 充血模式和贫血模式
- 贫血模型和充血模型
- 充血模型和贫血模型
- 充血模式和贫血模式
- 贫血模型和充血模型
- 谈谈领域模型--贫血还是充血?
- 学习杂记--- 贫血 充血 sql join
- 领域模型,贫血模型,充血模型
- Domain Object贫血vs富血(DDD)和spring roo到ruby的扯淡
- ASP.NET中使用MD5和SHA1算法加密
- 无法登录,提示是SA问题
- 搜索引擎工作原理
- Windows Shell 编程 第三章
- IE与firefox区别
- 从贫血到充血Domain Model
- MFC中读写postgres数据库bytea类型着重处
- 常用js程序代码
- Reporting Services及VS2005使用技巧记录
- PeekMessage 消息机制
- 密码学基础复习要点
- 适配器模式 Adapter Pattern
- 男性英文名字大全、释意
- Windows Shell 编程 第四章