java中级做dao模型_DAO-持久层-领域对象-贫血模型

原文

关于"贫血模型"的讨论几乎没有停止过,在openfans.org的开发过程中,我们也讨论了很久,我觉的有很多东西应该记下来:

明确一下意思先:

DAO:数据操作对象,会操作数据库

持久层:能提供对象持久化服务的一系列组件或服务

领域对象:描述领域模型的对象,是通过业务分析进行系统建模的产物

血模型:就是domain

object只有属性的getter/setter方法的纯数据类,所有的业务逻辑完全由一个所谓的Manager来完成(又称

TransactionScript),这种模型下的domain object被Martin Fowler称之为“贫血的domain

object”

常见的类基本结构如下:

一个业务数据类叫做Item,

一个DAO接口类叫做ItemDao

一个DAO接口实现类叫做ItemDaoHibernateImpl

一个业务逻辑类叫做ItemManager(或者叫做ItemService).

观察上面的几个类很容易发现问题:

1:Item和ItemManager实际是操作与数据的关系,实际完成的就是经典OO中的一个对象的能力;

2:当有许多Item时 类组变得很庞大,产生很多 xxxDao xxxImpl xxxManager 其中包含大量重复代码;

按<>的观点,上述代码存在以下臭味:

1:重复的代码   xxxDao xxxImpl xxxManager(通常)

2:霰弹式修改,一个变化影响多个类,类之间不够高内聚 item变化-->Dao,Impl,Manager均要变动

3:依恋情结,两个类之间互相作用过多 itemManager

4:平行继承体系,当增加一个新类时总是要增加另一个类

5:夸夸其谈未来性,在没有任何暗示的情况下考虑扩展  Dao,实际HibernateImpl可能n年内是唯一的Dao实现

6:纯稚的数据类,只有数据的类  item

我觉的 贫血模型 是系统分析设计方向性错误的产物:

1:没有进行领域建模---以数据表结构为中心,而不是业务模型为中心的思考方式,使设计人员选择Item为考虑问题的出发点

2:将DAO与持久层混淆---我们需要的一种持久化服务,DAO紧紧是提供数据操作能力而已,Hibernate是一种高级的服务(他已经包含了DAO,而不是相反),已经完成了所有的持久层服务.

3:过于强调低偶合---将一些本来一些提供单一职责的内容分散在多个单元中使 客户端 依赖更多的接口,而忘记了高内聚原则.

4:Spring的能力限制---由于Spring现阶段不支持对于领域模型的服务注入,使设计人员将操作和数据分开,并将领域变为DataOnly的.

(Spring2.0将在很大程度上解决这个问题)

我认为良好的解决方案:

首先领域建模,建立领域模型-->合并前面所说的Item和ItemManager成为 domainItem;对于数据库服务,

1:如果考虑领域层包含数据操作能力,则建立DAO并选择其它好的DAO方案比如IBATIS或Hibernate之类的组件;

2:如果考虑将数据库(或其他存储界质)存储考虑在领域之外成为持久层,

a:则或者对持久层框架同时建模,同时选择合适的组件为持久层服务提供存储服务(包括DAO--亦可选择IBATIS/Hibernate组件),

b:或者直接使用Hibernate/JDO等框架实现持久化服务,领域层直接使用持久层服务,对领域对象进行持久化和反持久化(从持久层获取以持久化的对象).

其他:

实际上,作为一种解决方案,所谓"贫血模型"的具体使用,并不会有太大的问题,尤其是使用一些代码生成工具或已经做好相应的基本框架时,很多软件的核心价

值都在于对客户提供的服务,而其内部则成为黑盒,我们只要合理的解决业务问题,就是"王道"了,对于代码的臭味,可以慢慢重构--这也需要成本呀.

再其他:

有人说,我们的业务就是CRUD,领域模型只有数据类就足够了.我觉的这是搞错了方向------只有CRUD时,只有处理CRUD的那些类才有必要进行建模(他们才是领域模型),而所谓的User\Item等数据类则完全没有必要进行建模,更不要谈领域了.

贫血之外:

实际上,软件\OO方法的外延大的很,更多问题与数据库存储无关(但也有贫血问题),所以建模才是根本,OO方法的原则才是我们必须掌握的.

posted on 2006-04-10 22:21 兼听则明 阅读(6312) 评论(4)  编辑  收藏 所属分类: oo

0232053637c9a6232ac71bd66946df4f.png

评论

# re: DAO-持久层-领域对象-贫血模型

2006-04-11 01:30

mixlee

典型的滥用接口  回复  更多评论

# re: DAO-持久层-领域对象-贫血模型

2007-10-20 13:02

邓英妥

不敢苟同楼主的观点  回复  更多评论

# re: DAO-持久层-领域对象-贫血模型

2008-10-20 17:40

mojie

合并前面所说的Item和ItemManager成为 domainItem,我认为贫血可以使,层次更清晰 ,便于模型维护  回复  更多评论

# re: DAO-持久层-领域对象-贫血模型[未登录]

2015-04-15 20:10

喔喔

同样不敢沟通楼主观点  回复  更多评论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JSP分页技术的实现(利用当前页进行前后加减,并利用href进行当前页面传值,传值当然是那个当前值变量)...

一、可滚动结果集 Connection con DriverManager.getConnection(); PreparedStatement stmt con.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY); ResultSet rs stmt.executeQuery(); 常用方法&#xff1a; (1)rs.absolute(n); 可以…

前端学习(1406):多人管理26邮箱地址是否存在

// 引入用户集合的构造函数 const { User, validateUser } require(../../model/user); // 引入加密模块 const bcrypt require(bcryptjs);module.exports async(req, res, next) > {try {await validateUser(req.body)} catch (e) {// 验证没有通过// e.message// 重定向…

我的世界JAVA刷怪范围_《我的世界》只有刷怪蛋能够刷新生物吗?并不是,还有一种物品!...

《我的世界》MC能够刷新生物的只有刷怪蛋吗&#xff1f;不&#xff0c;还有一种物品&#xff01;《我的世界》只有刷怪蛋能够刷新生物吗&#xff1f;并不是&#xff0c;还有一种物品&#xff01;在沙盒游戏《我的世界》里面&#xff0c;绝大部分的生物会自然生成于主世界、下界…

Android上传文件至服务器(转)

本实例实现每隔5秒上传一次&#xff0c;通过服务器端获取手机上传过来的文件信息并做相应处理&#xff1b;采用AndroidStruts2技术。 一、Android端实现文件上传 1)、新建一个Android项目命名为androidUpload&#xff0c;目录结构如下&#xff1a; 2)、新建FormFile类&#xff…

前端学习(1407):多人管理27代码优化

// 创建用户集合 // 引入mongoose第三方模块 const mongoose require(mongoose); // 导入bcrypt const bcrypt require(bcryptjs); // 引入joi模块 const Joi require(joi); // 创建用户集合规则 const userSchema new mongoose.Schema({username: {type: String,required:…

java enumerator_NSEnumerator使用

集合类(如&#xff1a;NSArray、NSSet、NSDictionary等)均可获取到NSEnumerator, 该类是一个抽象类&#xff0c;没有用来创建实例的公有接口。NSEnumerator的nextObject方法可以遍历每个集合元素&#xff0c;结束返回nil&#xff0c;通过与while结合使用可遍历集合中所有项。例…

前端学习(1408):多人管理28用户信息展示

userpage.js // 导入用户集合构造函数 const { User } require(../../model/user);module.exports async (req, res) > {// 接收客户端传递过来的当前页参数let page req.query.page || 1;// 每一页显示的数据条数let pagesize 10;// 查询用户数据的总数let count awa…

java c3p0获取主键_Tomcatc3p0配置jnid数据源2种实现方法解析

使用c3p0导入c3p0jar包com.mchangec3p00.9.5.2在tomcat的context.xml文件加入数据源配置auth"Container"description"DB Connection"driverClass"com.mysql.jdbc.Driver"maxPoolSize"100" minPoolSize"2"acquireIncrement&q…

前端学习(1409):多人管理29安装json转换工具

json转换工具 打开谷歌 chrome://flags/#extensions-on-chrome-urls

让struts2和servlet共存

由于struts2默认的是拦截全部的请求 由配置文件能够看出 <filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class></filter><filter-mapping…

php sslbug,PHP错误抑制符(@)导致引用传参失败Bug的分析

看下面的例子:$array array(1,2,3);function add (&$arr) {$arr[] 4;}add($array);print_r($array);/**此时, $array没有改变, 输出:Array([0] > 1[1] > 2[2] > 3)*/add($array);print_r($array);/**不使用错误抑制的情况下, 输出正常:Array([0] > 1[1] >…

前端学习(1410):多人管理30数据分页

// 导入用户集合构造函数 const { User } require(../../model/user);module.exports async (req, res) > {// 接收客户端传递过来的当前页参数let page req.query.page || 1;// 每一页显示的数据条数let pagesize 10;// 查询用户数据的总数let count await User.count…

MongoDB分析工具之三:db.currentOp()

db.currentOp() db.currentOp是个好东西&#xff0c;顾名思义&#xff0c;就是当前的操作。在mongodb中可以查看当前数据库上此刻的操作语句信息&#xff0c;包括insert/query/update/remove/getmore/command等多种操作。直接执行 db.currentOp()一般返回一个空的数组&#xff…

php 添加样式,添加样式到php html电子邮件

我仔细查看了这个问题,我在此发现的是添加以下内容&#xff1a;$headers MIME-Version: 1.0 . "\r\n";$headers . Content-type: text/html; charsetiso-8859-1 . "\r\n";和我想发送一个时事通讯类型的电子邮件,所以造型真的很重要.我观看的所有视频都只是…

前端学习(1411):多人管理31数据分页2

{{extend ./common/layout.art}}{{block main}}<!-- 子模板的相对路径相对的就是当前文件 因为它是由模板引擎解析的 而不是浏览器 -->{{include ./common/header.art}}<!-- 主体内容 --><div class"content">{{include ./common/aside.art}}<d…

软件推广

新闻是按照日历来做主导的&#xff0c;如果做的东西也和最近发生的事情有关的话&#xff0c;契合节假日&#xff08;突然想到春运&#xff09;&#xff0c;曝光率会增加在制作软件的同时就要考虑到如何推广。国内的视频公司在视频前的广告和适合做软件推广。新电影上映&#xf…

php按城市显示搜索结果,搜索结果页(通过数据库搜索)

_z2yJxW">本文档讲的是如何通过直接通过数据库搜索接口模板显示搜索结果页。接口&#xff1a;akcms_page.php一 首先在网站根目录创建一个php文件&#xff0c;文件名随便起比如&#xff1a;db_search.php&#xff0c;内容是&#xff1a;$template search.htm;include …

前端学习(1412):多人管理32修改

const { User } require(../../model/user);module.exports async (req, res) > {// 获取到地址栏中的id参数const { message, id } req.query;// 如果当前传递了id参数if (id) {// 修改操作let user await User.findOne({_id: id});// 渲染用户编辑页面(修改)res.rende…

真正能成功的人,不见得是最聪明的,也小见得是学历最高的,而是最能面对问题、锲而不舍的人。...

要知道&#xff0c;这世界上真正能成功的人&#xff0c;不见得是最聪明的&#xff0c;也小见得是学历最高的&#xff0c;而是最能面对问题、锲而不舍的人。 爸爸以前有个同学&#xff0c;追班上一个女生。这男生很不会说话&#xff0c;他开门见山就对女生讲“我爱你”。 那女生…

前端学习(1413):多人管理33修改2(未能完结)

// 引用expess框架 const express require(express); // 创建博客展示页面路由 const admin express.Router();// 渲染登录页面 admin.get(/login, require(./admin/loginPage));// 实现登录功能 admin.post(/login, require(./admin/login));// 创建用户列表路由 admin.get(…