- 浏览: 395141 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (325)
- 神经网络 (1)
- javascript (11)
- 数据结构 (2)
- 计算机图形学 (11)
- 模式识别 (1)
- 前端开发 (14)
- 机器学习 (11)
- ios开发 (50)
- Python (9)
- HTML5 (4)
- 计算机视觉 (9)
- 数字图像处理 (7)
- 架构设计 (19)
- 数据库设计 (9)
- 算法设计 (59)
- Java (37)
- 其他 (3)
- 游戏开发 (5)
- c++ (17)
- Linux (3)
- TCP/IP (2)
- Flex (41)
- 健康 (6)
- AI (2)
- 工具 (1)
- 数据挖掘 (1)
- 性能优化 (6)
- 综合 (2)
- 网络通信 (12)
- Android (2)
- UML (3)
- 软件设计 (11)
- 编程经验 (7)
- J2EE (1)
- 多媒体技术 (3)
- 数学 (7)
- php (4)
- 设计 (1)
- CS (2)
- 计算机理论 (1)
- 信息安全 (1)
最新评论
-
ahead_zhan:
good good good
flex3控件_ModuleLoader -
lonerzf:
好样的。非常感谢楼主
OpenCV视频教程整理 -
lonerzf:
好样的。谢谢~
OpenCV视频教程整理 -
coding1688:
博主说的不错,我在实现瀑布流布局时也用的masonry插件,有 ...
Javascript 瀑布流式布局及其动态效果的实现 -
snowolf:
除非玩游戏,不然没啥win的事情,或者用win的银行客户端,通 ...
macbook安装操作系统的机理分析
参考: http://www.uml.org.cn/mxdx/200907132.asp
在当前的开发者社区,广泛流行一种被Martin Fowler称为贫血领域模型的构架模式。该模式由于大师的批判而饱受指责。这个模式有个致命的缺陷:在处理复杂领域时常常表现不佳。很多迹象表明,当我们面对复杂应用时,最好还是转向一个基于丰富领域模型的构架。
尽管丰富领域模型有着显而易见的好处,但也给实践带来了挑战,这既有构建技术上的原因,也有设计方法上的原因。对于构建技术,如Annotation、Aspect和DI等复杂技术的使用,最终能够清晰的被掌握,但在设计方法上,往往由于实践的不同而难以取得共识。
本文的目的仅仅是在技术上给出一种由贫血领域模型向丰富领域模型转换的方案,供有相同需要的同行参考。
1.前提和限制
无论使用哪种领域模型,通常都需要借助一些工具的支持,这些工具包括Ioc容器和O/R映射工具。因作者经验所限,当提及这些工具时,只意味着Java世界里的Spring和Hibernate。
有关贫血领域模型的论述请参考:
http://www.martinfowler.com/bliki/AnemicDomainModel.html
贫血领域模型的最佳实践请参考:
丰富领域模型的最权威指南请访问:
http://www.domaindrivendesign.org
由于语境的不同,不同的分层模式的术语具有不同的含义,但它们所要实现的任务,是可以分离出来的,而这些任务,目前还没有造成广泛的语义混乱。为了更好的比较本文中提及的两种构架模式,将它们所要完成的任务定义如下:
任务 |
描述 |
表现逻辑 |
接收来自系统外部的请求,将请求代理到其他模块,并将返回的处理结果,通过某种方式呈现给请求者。 |
应用逻辑 |
是用例的外观的实现,协调用例的真正实现者完成一次应用程序相关的功能。 |
领域逻辑 |
对问题领域最本质内容进行建模,实现体现用户核心价值的功能。 |
持久化逻辑 |
与数据的外部存储交互。 |
基础服务 |
更加的以技术为中心,为软件系统的各模块提供基础支持。 |
2.贫血领域模型构架
2.1.分层模式
即使同样打着贫血模型的标签,它们也会有不同的风格。下面是比较典型的一种:
层 |
任务 |
对象 |
描述 |
表现层 |
表现逻辑 |
模型对象 |
Model。领域层中的实体/值对象,也可以用独立的对象。 |
视图 |
View |
||
控制器 |
Controller。通过某种机制而获得对用户请求的响应。 |
||
领域层 |
在领域逻辑中混合了应用逻辑 |
服务 |
Service。同时处理领域逻辑和应用逻辑 |
实体 |
Entity。领域模型的静态视图 |
||
数据源层 |
持久化逻辑 |
DAO对象 |
有很多实现方式,如JDBC、Hibernate、iBATIS、JPA、EJB CMP |
基础设施层 |
基础服务 |
|
|
2.2.示例代码
现在假设有一个在线购物网站,我们要浏览产品列表,然后选中了一个感兴趣的产品,此时我们需要查看该产品的详细信息。
1)页面发出请求
下面是一个可能的JSF代码片断:
<h:commandlink value="#{product.name}" action="#{product.edit}"></h:commandlink> <f:param value="#{product.id}" name="productid"></f:param>
|
2)分派到控制器
假设请求被调度到控制器yourpackage.action.ProductAction:
package yourpackage.action; ...... public class ProductAction extends BaseAction { //通过依赖注入的服务 private ProductService productService; //作为模型对象的领域对象 private Product product; private Integer id; //响应查看产品信息的事件 public String edit() { product = productService.getProduct(id); return “product”; //JSF将其解析为product.xhtml视图 } } |
3)领域层的服务
一般会有一个服务接口ProductService,然后是该接口的实现ProductServiceImpl:
package yourpackage.service; ...... public class ProductServiceImpl extends BaseService implements ProductService { //通过依赖注入的DAO对象 private ProductDao productDao; //获取产品信息的领域逻辑方法 public Product getProduct(Integer id) { return productDao.getProduct(id); } } |
4)领域层的实体
下面是JPA风格的实体,该实体仅用于承载数据,而没有领域行为(贫血之说由此而来)。
package yourpackage.model; ...... @Entity public class Product { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="Id") public Long getId() { return id; }
@Column(name="Name", length=30, nullable=false) public String getName() { return name; } } |
5)DAO对象
这里同样需要一个接口,其实现类如果用JPA的话:
package yourpackage.dao; ...... public class ProductDaoJpa extends BaseDaoJpa implements ProductDao { public Product getProduct(Integer id) { return (Product) getJpaTemplate().find(Product.class, id);; } ...... } |
2.3.分析
优点:
* 获得了分层的最基本的好处。
* 易于理解,快速掌握:没有采用更复杂的技术,并且有丰富的示例资源。
* 有广泛的工具支持,非常容易的从Spring/Hibernate类型的框架获益。
* 适合于模型简单,以CRUD操作为主的领域。
缺点:
* 模型的领域表达能力欠缺。
* 代码职责分配不合理。
3. 丰富领域模型
3.1分层模式
典型的DDD风格的分层模式如下:
层 |
任务 |
对象 |
描述 |
表现层 |
表现逻辑 |
模型对象 |
领域层中的实体/值对象,也可以用独立的对象。 |
视图 |
|
||
控制器 |
|
||
应用层 |
应用逻辑 |
服务 |
对用例建模 |
领域层 |
领域逻辑 |
服务 |
对领域操作建模 |
实体 |
对领域概念建模、并可被持久化 |
||
值对象 |
Value Object。对领域概念建模 |
||
存储库 |
Repository。隔离持久化 |
||
基础设施 |
持久化逻辑和基础服务 |
数据映射 |
通常以DAO模式封装持久化操作 |
基础服务 |
|
在实践中,我个人更倾向于将数据映射从基础设施层分离出来,这样会有一个更清晰的层次结构。
无论哪种领域模型,在是否将领域对象传递到表现层作为模型数据的问题上一直存在争议。要做出恰当的设计决定,需要在灵活性和严谨性之间做出平衡。有一些技术上的方法可以使领域对象在作为DTO对象进行传递时得到保护,可以参考下面的文章《Protecting the Domain Model》:
http://api.blogs.com/the_catch_blog/2005/05/protecting_the_.html
这些做法在一定程度上弥补了直接传递领域对象带来的负面影响。
3.2有什么不同?
从上面的表格我们可以发现,要做的事还是那些事,只不过部分职责被重新分配了而已。相对于贫血领域模型,在新的分层模式中:
* 不变的是表现层;
* 被合并的是数据源层,现在成了基础设施的一部分;
* 增加的是应用层;
* 被重新组织的是领域层,其职责被分配到相应的对象中:实体、值对象、服务和存储库。
这里最大的变化有三个:
1)应用逻辑被从领域逻辑中独立出来,形成了新的应用层。该层的接口按照用例进行设计,因此粒度较大;该层反映的是用系统所实现的任务,如果需要,也能反映工作流程。
2)领域层只反映领域逻辑中最核心部分,因此也是最复杂的(如果领域复杂程度超过技术复杂程度的话)。其中的实体不但持有数据,还具备丰富的行为;服务是一些领域相关的操作(这不同于应用层的服务,更不同于基础设施层的服务);通过存储库隔离了与数据技术的联系。
3)领域层可以独立地访问其他层的服务和资源。这是一个有争议的话题,同时很有技术上的挑战性,下文会通过实例代码进行说明。
4.重构到丰富领域模型构架
4.1.技术方案
为了简便起见,下文中使用A和B这两个别名分别代表“贫血领域模型”和“丰富领域模型”,使用名称空间表示模型中的层,如B::应用层表示丰富领域模型的应用层。
通过前面的比较,可以很容易的得到下面转换的方案:
1)保持表现层不变
2)分离出来应用层。从A::领域层移出应用逻辑形成B::应用层。
3)重构一个纯粹的领域层。将A::领域层的领域逻辑部分进行分解:
# 将概念性的逻辑重构到B::领域层.实体和B::领域层.值对象;
# 将操作性逻辑重构到B::领域层.服务;
# 将数据源访问抽象为存储库接口,存储库的实现由Ioc容器注入。
4)重构数据访问对象,使其实现领域层的存储库接口。
5)基础设施层保持不变。
不多做解释,下面通过代码进行说明。
4.2. 示例代码
还是前面的在线购物网站,但这次使用了一个稍微能体现领域逻辑的用例:列出与当前产品相关的其他产品。
1)页面发出请求
下面是一个可能的JSF代码片断:
- <h:commandLink action="#{product.related}" value="#{相关产品}">
- <f:param name="productid" value="#{product.id}" />
- weaver>
- aspectj>
然后,需要在JVM加载参数中指定下面的内容:
-javaagent: <path-to-ajlibs>/aspectjweaver.jar</path-to-ajlibs> |
现在可以说大功告成了。
5)DAO对象
现在DAO需要实现的接口变成了领域层的ProductRepository:
package yourpackage.dao; import yourpackage.domain; ...... public class ProductDaoJpa extends BaseDaoJpa implements ProductRepository { public Product getProduct(Integer id) { return (Product) getJpaTemplate().find(Product.class, id);; } public Product getRelatedProduct(Integer id) { //这里是具体的实现代码 } } |
5.结论
要构建一个纯粹的领域模型,往往需要在领域对象中直接使用外部服务,如数据库访问,外部资源,或其他必要的服务。在没有强大的Annotation、AOP及DI技术的支持下,这些外部服务或资源很难被注入到领域对象中,由此形成了贫血模型的设计风格。
特别地,对于Spring用户来说,在2.0版发布之后,问题的解决变得更容易一些。利用Spring集成的AspectJ实现向领域对象进行依赖注入,可以使领域对象可以表达更丰富的逻辑,从而过渡到丰富领域模型。在这个关键问题解决之后,剩下的问题也就迎刃而解了。
发表评论
-
nginx上搭建HLS流媒体服务器
2013-07-28 13:31 1342转自:http://blog.csdn.net/ ... -
数据库设计原则
2012-07-17 17:38 716参考:http://www.cnblogs.com/wuhen ... -
使用SQL生成非均匀随机数
2012-07-14 12:06 1036参考: http://www.cnblogs.com/ ... -
NoSQL架构实践(一)——以NoSQL为辅
2011-10-25 23:36 683参考:http://www.infoq.com/cn/n ... -
MySQL数据库分表的3种方法
2011-10-25 11:05 1265参考:http://club.topsage.com/foru ... -
精通Hibernate——映射一对多关联关系
2011-04-17 01:38 986在域模型(实体域)中,关联关系是类与类之间最普遍的关系。根据U ... -
HIbernate注解
2011-04-07 10:37 864Hibernate注解 文章分类:Web前端 @o ... -
cairngorm注意事项
2011-02-27 11:03 791这两天玩了一下 ... -
如何规划Logger的输出日志级别
2010-11-10 11:56 1186欢迎大家补充相关日志级别的输出规范与远景,谢谢。 一个 ... -
SNS中好友动态功能的设计思路
2010-11-07 14:54 1102参考:http://hi.baidu.com/worldpre ... -
贫血模式 领域模式
2010-11-03 11:09 1097参考:http://mabusyao.iteye.com/bl ... -
Spring Hibernate使用TransactionInterceptor声明式事务配置
2010-11-01 11:12 1163<!-- 事务管理器 --> <be ... -
四色原型
2010-10-24 11:22 728参考:http://www.jdon.com/md ... -
HibernateDaoSupport与JdbcDaoSupport总结
2010-10-23 11:14 928Spring框架中Dao支持总 ... -
数据库中表的十二个设计原则
2010-10-19 14:30 1001(1)、不应针对整个系 ... -
j2ee jar包
2010-07-28 22:31 3029* ant/ant.jar, ant/ant-launcher ... -
Access、SQLite、HSQLDB、Sybase、MySQL、DB4O比较
2010-07-17 16:13 2096本文转自:http://blog.sin ...
相关推荐
贫血模型or领域模型的举例对比,让你初步了解贫血模型与领域模型的区别和概念
贫血模型or领域模型的举例对比,让你初步了解贫血模型与领域模型的区别和概念。附加一个自己创建的代码范例
为了使问题具有确定性,我想从一个简单例子着手,用我对贫血模型和领域模型的概念来分别实现例子。至于我的理解对与否,大家可以做评判,至少有个可以评判的标准在这。一个例子我要举的是一个银行转帐的例子,又是一...
失血模型简单来说,就是domain object只有属性的getter/setter方法的纯数据类,所有的业务逻辑完全由business object来完成(又称TransactionScript),这种模型下的domain object被Martin Fowler称之为“贫血的domain...
领域模型的职责是实现业务逻辑,如果领域模型只是用来处理简单的逻辑(比如贫血模型),那么领域模型的作用微乎其微,甚至可以忽略,数据转换的成本比领域模型带来的好处还多,这种情况其实就是在原有的分层架构中...
最近taowen同学连续发起了两起关于贫血模型和领域模型的讨论,引起了大家的广泛热烈...为了使问题具有确定性,我想从一个简单例子着手,用我对贫血模型和领域模型的概念来分别实现例子。至于我的理解对与否,大家可以做
本文解释了当今比较新的设计模式中的贫血和充血模式。对加深理解二模型很有帮助!
这种模型化的设计方法在项目应用中体现得非常之多.http://forum.javaeye.com/viewtopic.php?t=17579在JavaEye的这个帖子中,大牛robbin总结了4种常见的领域模型,并分析了它们的优缺点.1、失血模型2、贫血模型Service...
DDD从战略设计到战术设计概览 第2章 领域分析模型 核心域,支撑子域,通用子域 微服务和DDD是什么关系? 传统模式下如何合理的划分各种域 基于DDD的方式进行域划分 什么是通用语言 什么是限界上下文? 限界上下文和...
医疗保健类化学药行业抗贫血药领域分析报告(研究报告).pdf
2020年医疗保健化学药行业抗贫血药领域行业分析报告(市场调查报告).pdf
本文将对传统三层架构和对应的领域模型架构、以及每个模块的职责进行简单的说明。下图即示范项目的模块结构:传统三层架构是一种软件架构,是一种典型的、基于贫血模型的、面向过程的JavaWeb分层方式。该架构分为...
行业分类-设备装置-一种建立小鼠重型再生障碍性贫血模型的方法.zip
第一点原因是,大部分情况下,我们开发的系统业务可能都比较简单,简单到就是基于 第二点原因是,充血模型的设计要比贫血模型更加有难度 第三点原因是,思维已固化,转型
缺铁性贫血病历模板.doc
基于BP神经网络模型的低增生性骨髓增生异常综合征与再生障碍性贫血的鉴别诊断研究.pdf