- 浏览: 2876686 次
- 性别:
- 来自: 武汉
文章分类
- 全部博客 (1173)
- 名言警句 (5)
- 心情随笔 (50)
- 数据库 (57)
- Java基础 (241)
- J2EE框架 (91)
- 数据结构 (12)
- 程序设计 (21)
- WEB技术 (128)
- 网络日志 (12)
- IT资讯 (247)
- linux (64)
- solaris (2)
- 其它 (143)
- WebService (4)
- 日语学习 (2)
- 机器人 (5)
- Android (5)
- cgywin (3)
- Game (1)
- DWR (1)
- spring (8)
- canvas (1)
- Guava (3)
- Modbus (5)
- 测试 (6)
- mongodb (9)
- Quartz (2)
- Cron (1)
- windows (2)
- 持续集成 (1)
- bootstrap (3)
- 结对编程 (1)
- nodejs (1)
- Netty (1)
- 安全 (3)
- webstorm (2)
- sparkline (1)
- Job (1)
- git (3)
- Maven (3)
- knockout (5)
- jquery (1)
- bower (1)
- docker (1)
- confluence (4)
- wiki (1)
- GoogleMap (1)
- jekyll (10)
- ruby (2)
- npm (3)
- browserify (1)
- gulp (3)
- openwrt (1)
- discuz (3)
- 输入法 (1)
- JPA (1)
- eclipse (2)
- IntelliJ (1)
- css (1)
- 虚拟机 (1)
- 操作系统 (1)
- azkaban (2)
- scrum (1)
最新评论
-
pangxiea_:
你好, 想请问一下 Linux下 这么使用rxtxcomm 在 ...
使用Java进行串口通信 -
abababudei:
请教一下,这个您是怎么解决的:/dev/ttyS2enteri ...
Java应用程序的MODBUS通讯 -
xuniverse:
hannibal005 写道楼主,我问下 request.se ...
用javascript与java进行RSA加密与解密 -
atxkm:
找了一下午,终于找到了
gulp 拷贝文件时如何移除文件目录结构 -
kalogen:
gtczr 写道非常感谢,经过我自己的修改,已经完美实现。发出 ...
用javascript与java进行RSA加密与解密
有兴趣可看此处原文及相关讨论:总结一下最近关于domain object以及相关的讨论
======================================
在最近的围绕domain object的讨论中浮现出来了三种模型,(还有一些其他的旁枝,不一一分析了),经过一番讨论,各种问题逐渐清晰起来,在这里我试图做一个总结,便于大家了解和掌握。
第一种模型:只有getter/setter方法的纯数据类,所有的业务逻辑完全由business
object来完成(又称TransactionScript),这种模型下的domain object被Martin
Fowler称之为“贫血的domain
object”。下面用举一个具体的代码来说明,代码来自Hibernate的caveatemptor,但经过我的改写:
一个实体类叫做Item,指的是一个拍卖项目
一个DAO接口类叫做ItemDao
一个DAO接口实现类叫做ItemDaoHibernateImpl
一个业务逻辑类叫做ItemManager(或者叫做ItemService)
- public class Item implements Serializable {
- private Long id = null ;
- private int version;
- private String name;
- private User seller;
- private String description;
- private MonetaryAmount initialPrice;
- private MonetaryAmount reservePrice;
- private Date startDate;
- private Date endDate;
- private Set categorizedItems = new HashSet();
- private Collection bids = new ArrayList();
- private Bid successfulBid;
- private ItemState state;
- private User approvedBy;
- private Date approvalDatetime;
- private Date created = new Date();
- // getter/setter方法省略不写,避免篇幅太长
- }
public class Item implements Serializable { private Long id = null; private int version; private String name; private User seller; private String description; private MonetaryAmount initialPrice; private MonetaryAmount reservePrice; private Date startDate; private Date endDate; private Set categorizedItems = new HashSet(); private Collection bids = new ArrayList(); private Bid successfulBid; private ItemState state; private User approvedBy; private Date approvalDatetime; private Date created = new Date(); // getter/setter方法省略不写,避免篇幅太长 }
- public interface ItemDao {
- public Item getItemById(Long id);
- public Collection findAll();
- public void updateItem(Item item);
- }
public interface ItemDao { public Item getItemById(Long id); public Collection findAll(); public void updateItem(Item item); }
ItemDao定义持久化操作的接口,用于隔离持久化代码。
- public class ItemDaoHibernateImpl implements ItemDao extends HibernateDaoSupport {
- public Item getItemById(Long id) {
- return (Item) getHibernateTemplate().load(Item. class , id);
- }
- public Collection findAll() {
- return (List) getHibernateTemplate().find( "from Item" );
- }
- public void updateItem(Item item) {
- getHibernateTemplate().update(item);
- }
- }
public class ItemDaoHibernateImpl implements ItemDao extends HibernateDaoSupport { public Item getItemById(Long id) { return (Item) getHibernateTemplate().load(Item.class, id); } public Collection findAll() { return (List) getHibernateTemplate().find("from Item"); } public void updateItem(Item item) { getHibernateTemplate().update(item); } }
ItemDaoHibernateImpl完成具体的持久化工作,请注意,数据库资源的获取和释放是在ItemDaoHibernateImpl
里面处理的,每个DAO方法调用之前打开Session,DAO方法调用之后,关闭Session。(Session放在ThreadLocal中,保证
一次调用只打开关闭一次)
- public class ItemManager {
- private ItemDao itemDao;
- public void setItemDao(ItemDao itemDao) { this .itemDao = itemDao;}
- public Bid loadItemById(Long id) {
- itemDao.loadItemById(id);
- }
- public Collection listAllItems() {
- return itemDao.findAll();
- }
- public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount,
- Bid currentMaxBid, Bid currentMinBid) throws BusinessException {
- if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0 ) {
- throw new BusinessException( "Bid too low." );
- }
- // Auction is active
- if ( !state.equals(ItemState.ACTIVE) )
- throw new BusinessException( "Auction is not active yet." );
- // Auction still valid
- if ( item.getEndDate().before( new Date() ) )
- throw new BusinessException( "Can't place new bid, auction already ended." );
- // Create new Bid
- Bid newBid = new Bid(bidAmount, item, bidder);
- // Place bid for this Item
- item.getBids().add(newBid);
- itemDao.update(item); // 调用DAO完成持久化操作
- return newBid;
- }
- }
public class ItemManager { private ItemDao itemDao; public void setItemDao(ItemDao itemDao) { this.itemDao = itemDao;} public Bid loadItemById(Long id) { itemDao.loadItemById(id); } public Collection listAllItems() { return itemDao.findAll(); } public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount, Bid currentMaxBid, Bid currentMinBid) throws BusinessException { if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0) { throw new BusinessException("Bid too low."); } // Auction is active if ( !state.equals(ItemState.ACTIVE) ) throw new BusinessException("Auction is not active yet."); // Auction still valid if ( item.getEndDate().before( new Date() ) ) throw new BusinessException("Can't place new bid, auction already ended."); // Create new Bid Bid newBid = new Bid(bidAmount, item, bidder); // Place bid for this Item item.getBids().add(newBid); itemDao.update(item); // 调用DAO完成持久化操作 return newBid; } }
事务的管理是在ItemManger这一层完成的,ItemManager实现具体的业务逻辑。除了常见的和CRUD有关的简单逻辑之外,这里还有一个placeBid的逻辑,即项目的竞标。
以上是一个完整的第一种模型的示例代码。在这个示例中,placeBid,loadItemById,findAll等等业务逻辑统统放在ItemManager中实现,而Item只有getter/setter方法。
第二种模型,也就是Martin Fowler指的rich domain object是下面这样子的:
一个带有业务逻辑的实体类,即domain object是Item
一个DAO接口ItemDao
一个DAO实现ItemDaoHibernateImpl
一个业务逻辑对象ItemManager
- public class Item implements Serializable {
- // 所有的属性和getter/setter方法同上,省略
- public Bid placeBid(User bidder, MonetaryAmount bidAmount,
- Bid currentMaxBid, Bid currentMinBid)
- throws BusinessException {
- // Check highest bid (can also be a different Strategy (pattern))
- if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0 ) {
- throw new BusinessException( "Bid too low." );
- }
- // Auction is active
- if ( !state.equals(ItemState.ACTIVE) )
- throw new BusinessException( "Auction is not active yet." );
- // Auction still valid
- if ( this .getEndDate().before( new Date() ) )
- throw new BusinessException( "Can't place new bid, auction already ended." );
- // Create new Bid
- Bid newBid = new Bid(bidAmount, this , bidder);
- // Place bid for this Item
- this .getBids.add(newBid); // 请注意这一句,透明的进行了持久化,但是不能在这里调用ItemDao,Item不能对ItemDao产生依赖!
- return newBid;
- }
- }
public class Item implements Serializable { // 所有的属性和getter/setter方法同上,省略 public Bid placeBid(User bidder, MonetaryAmount bidAmount, Bid currentMaxBid, Bid currentMinBid) throws BusinessException { // Check highest bid (can also be a different Strategy (pattern)) if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0) { throw new BusinessException("Bid too low."); } // Auction is active if ( !state.equals(ItemState.ACTIVE) ) throw new BusinessException("Auction is not active yet."); // Auction still valid if ( this.getEndDate().before( new Date() ) ) throw new BusinessException("Can't place new bid, auction already ended."); // Create new Bid Bid newBid = new Bid(bidAmount, this, bidder); // Place bid for this Item this.getBids.add(newBid); // 请注意这一句,透明的进行了持久化,但是不能在这里调用ItemDao,Item不能对ItemDao产生依赖! return newBid; } }
竞标这个业务逻辑被放入到Item中来。请注意this.getBids.add(newBid);
如果没有Hibernate或者JDO这种O/R
Mapping的支持,我们是无法实现这种透明的持久化行为的。但是请注意,Item里面不能去调用ItemDAO,对ItemDAO产生依赖!
ItemDao和ItemDaoHibernateImpl的代码同上,省略。
- public class ItemManager {
- private ItemDao itemDao;
- public void setItemDao(ItemDao itemDao) { this .itemDao = itemDao;}
- public Bid loadItemById(Long id) {
- itemDao.loadItemById(id);
- }
- public Collection listAllItems() {
- return itemDao.findAll();
- }
- public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount,
- Bid currentMaxBid, Bid currentMinBid) throws BusinessException {
- item.placeBid(bidder, bidAmount, currentMaxBid, currentMinBid);
- itemDao.update(item); // 必须显式的调用DAO,保持持久化
- }
- }
public class ItemManager { private ItemDao itemDao; public void setItemDao(ItemDao itemDao) { this.itemDao = itemDao;} public Bid loadItemById(Long id) { itemDao.loadItemById(id); } public Collection listAllItems() { return itemDao.findAll(); } public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount, Bid currentMaxBid, Bid currentMinBid) throws BusinessException { item.placeBid(bidder, bidAmount, currentMaxBid, currentMinBid); itemDao.update(item); // 必须显式的调用DAO,保持持久化 } }
在第二种模型中,placeBid业务逻辑是放在Item中实现的,而loadItemById和findAll业务逻辑是放在
ItemManager中实现的。不过值得注意的是,即使placeBid业务逻辑放在Item中,你仍然需要在ItemManager中简单的封装一
层,以保证对placeBid业务逻辑进行事务的管理和持久化的触发。
这种模型是Martin Fowler所指的真正的domain
model。在这种模型中,有三个业务逻辑方法:placeBid,loadItemById和findAll,现在的问题是哪个逻辑应该放在Item
中,哪个逻辑应该放在ItemManager中。在我们这个例子中,placeBid放在Item中(但是ItemManager也需要对它进行简单的封
装),loadItemById和findAll是放在ItemManager中的。
切分的原则是什么呢? Rod Johnson提出原则是“case by case”,可重用度高的,和domain object状态密切关联的放在Item中,可重用度低的,和domain object状态没有密切关联的放在ItemManager中。
我提出的原则是:看业务方法是否显式的依赖持久化。
Item的placeBid这个业务逻辑方法没有显式的对持久化ItemDao接口产生依赖,所以要放在Item中。请注意,如果脱离了Hibernate这个持久化框架,Item这个domain object是可以进行单元测试的,他不依赖于Hibernate的持久化机制。它是一个独立的,可移植的,完整的,自包含的域对象
。
而loadItemById和findAll这两个业务逻辑方法是必须显式的对持久化ItemDao接口产生依赖,否则这个业务逻辑就无法完成。
如果你要把这两个方法放在Item中,那么Item就无法脱离Hibernate框架,无法在Hibernate框架之外独立存在。
第三种模型印象中好像是firebody或者是Archie提出的(也有可能不是,记不清楚了),简单的来说,这种模型就是把第二种模型的domain
object和business object合二为一了。所以ItemManager就不需要了,在这种模型下面,只有三个类,他们分别是:
Item:包含了实体类信息,也包含了所有的业务逻辑
ItemDao:持久化DAO接口类
ItemDaoHibernateImpl:DAO接口的实现类
由于ItemDao和ItemDaoHibernateImpl和上面完全相同,就省略了。
- public class Item implements Serializable {
- // 所有的属性和getter/setter方法都省略
- private static ItemDao itemDao;
- public void setItemDao(ItemDao itemDao) { this .itemDao = itemDao;}
- public static Item loadItemById(Long id) {
- return (Item) itemDao.loadItemById(id);
- }
- public static Collection findAll() {
- return (List) itemDao.findAll();
- }
- public Bid placeBid(User bidder, MonetaryAmount bidAmount,
- Bid currentMaxBid, Bid currentMinBid)
- throws BusinessException {
- // Check highest bid (can also be a different Strategy (pattern))
- if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0 ) {
- throw new BusinessException( "Bid too low." );
- }
- // Auction is active
- if ( !state.equals(ItemState.ACTIVE) )
- throw new BusinessException( "Auction is not active yet." );
- // Auction still valid
- if ( this .getEndDate().before( new Date() ) )
- throw new BusinessException( "Can't place new bid, auction already ended." );
- // Create new Bid
- Bid newBid = new Bid(bidAmount, this , bidder);
- // Place bid for this Item
- this .addBid(newBid);
- itemDao.update(this ); // 调用DAO进行显式持久化
- return newBid;
- }
- }
public class Item implements Serializable { // 所有的属性和getter/setter方法都省略 private static ItemDao itemDao; public void setItemDao(ItemDao itemDao) {this.itemDao = itemDao;} public static Item loadItemById(Long id) { return (Item) itemDao.loadItemById(id); } public static Collection findAll() { return (List) itemDao.findAll(); } public Bid placeBid(User bidder, MonetaryAmount bidAmount, Bid currentMaxBid, Bid currentMinBid) throws BusinessException { // Check highest bid (can also be a different Strategy (pattern)) if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0) { throw new BusinessException("Bid too low."); } // Auction is active if ( !state.equals(ItemState.ACTIVE) ) throw new BusinessException("Auction is not active yet."); // Auction still valid if ( this.getEndDate().before( new Date() ) ) throw new BusinessException("Can't place new bid, auction already ended."); // Create new Bid Bid newBid = new Bid(bidAmount, this, bidder); // Place bid for this Item this.addBid(newBid); itemDao.update(this); // 调用DAO进行显式持久化 return newBid; } }
在这种模型中,所有的业务逻辑全部都在Item中,事务管理也在Item中实现。
转自:http://www.iteye.com/topic/11712
发表评论
-
前端与后端的测试工具组合
2015-01-15 13:03 2187在Java领域,Apache, Spring, JBoss ... -
Design Pattern Categorization
2014-12-12 15:44 669Learning JavaScript Design P ... -
Java Design Patters Details
2014-12-05 14:10 709By Jason McDonald ABOUT DESIG ... -
单例模式(singleton)的一种写法
2014-12-05 11:26 608public class ModbusDetai ... -
Use Builder pattern to avoid method has too many parameters
2014-01-21 09:44 815sometimes, we have a class ... -
函数和方法的迪米特法则
2013-06-28 10:39 1037有一个方法M,它存在于对象O中。对象O的M方法只引用下面几种 ... -
Java编程中“为了性能”尽量要做到的一些地方
2012-03-09 19:07 1169最近的机器内存又爆满了,除了新增机器内存外,还应该好好re ... -
软件天才都是训练出来的
2011-01-03 11:15 1200长期以来,“软件业 ... -
Quest JProbe最佳实践指南
2010-11-25 17:42 18521. 介绍 在Java的广泛 ... -
2010年大规模技术架构的思路
2010-03-21 18:16 971相比其他行业,IT技术由于信息流动便捷,新技术更新非常频繁。架 ... -
领域驱动设计和开发实战
2009-06-05 13:20 1613背景 领域驱动设计(DDD)的中心内容是如何将业务领域概念映 ... -
基于Zigbee协议的OSGi无线家庭网关设计
2009-03-16 10:23 32191 引言 随着internet的 ... -
软件性能问题的几点分析
2009-01-19 15:52 1398【IT168技术分析】 2008年已经过去了,忙忙碌碌的 ... -
怎样成为优秀的软件架构师
2008-12-13 12:39 1741【IT168 评论文章】 近来读了一篇《怎样成 ... -
写给我的团队-代码篇
2008-11-30 23:16 1390看了neora的大作写给我 ... -
各大型网站架构分析收集
2008-11-26 23:24 24971. PlentyOfFish 网站架构学 ... -
一次性能调优的实战
2008-09-02 15:42 1473【IT168技术文档】 项目 ... -
用户故事估算技巧
2008-09-02 12:47 1635用2的幂进行估算 开始 ... -
ie和firefox中img对象区别的困惑
2008-08-20 16:45 2433在调试js时遇到一些恶心的问题,于是做了一个测试程序,放到网上 ... -
UML我拿什么来用你?
2008-08-04 09:59 1367【IT168分析评论】或许我这样评价不是很公正! 因为UML ...
相关推荐
### MFC SDI 制作 Office 2007 样式 Robbin 菜单 #### 一、概述 Microsoft Foundation Classes (MFC) 是一个由微软开发的类库,用于简化 Windows 应用程序的开发过程。本文档旨在介绍如何在 MFC 单文档界面...
Robbin Fan—运营专业型社区的经验和反思.ppt
robbin_site 是范凯的个人网站 http://robbinfan.com 网站的源码。 标签:robbin
在Javaeye Robbin的讨论中,他提到了缓存技术在多种场景下的应用和重要性。 **缓存的作用** 1. **高速缓冲存储**:缓存是一种位于主存储器和慢速I/O设备之间的高速存储器,其目的是减少对慢速设备的访问次数,提高...
在本文中,我们将深入探讨Git的一些常用命令,这些命令对于日常开发和协作至关重要。 首先,配置Git是使用它的第一步。通过`git config`命令,我们可以设置用户信息,如用户名和邮箱,以及自定义别名以简化命令输入...
《Ribbon for Delphi 10.1 Berlin:构建现代用户界面的新篇章》 在软件开发领域,Delphi作为一款强大的RAD(快速应用开发)工具,一直以来都深受开发者喜爱。而Ribbon界面设计则是在微软Office系列软件中广泛应用的...
1. **MVC模式**:Struts2是基于Model-View-Controller(MVC)设计模式的,它将业务逻辑、数据模型和用户界面分离,提高了代码的可维护性和可重用性。 2. **Action类**:每个用户请求都会映射到一个Action类,这是...
4. **MVVM模式**:WPF常使用的模型-视图-视图模型(MVVM)设计模式,有助于解耦视图和业务逻辑。 5. **依赖属性**:WPF中的一个重要特性,用于实现数据绑定和属性继承。 6. **命令**:理解ICommand接口和命令模式,...
让我们深入探讨这些组件以及它们如何整合。 1. **Eureka**:Eureka是Spring Cloud中的服务注册与发现组件。它是一个基于REST的服务,用于定位服务,使服务能够相互发现。每个微服务启动时,会向Eureka Server注册...
GE在韦尔奇任内20年实现了每年30%的高速增长,市值曾经达到全球第2,是全球最著名的CEO楷模。韦尔奇写的两本书:一本自传,一本Winning我读了很多遍,我觉得最有意思的反差是,尽管韦尔奇整个职业生涯都在GE渡过,...
此外,Robbin的研究揭示了森林破碎化对鸟类种群的影响,Ambuel和S.A Temple则分析了南部威斯康星州森林鸟类社区和植被的变化,强调了面积依赖性的生态效应。 Liu的《乡村景观规划》(2003)探讨了乡村景观的保护和...
资源名称:Struts2技术内幕:深入解析Struts架构设计与实现原理内容简介:本书由国内极为资深的Struts2技术专家(网名:downpour)亲自执笔,iteye兼CSDN产品总监范凯(网名:robbin)以及51CTO等技术社区鼎力推荐。...
这篇文章将详细探讨“获取IP地址的方法与示例”,并基于提供的标签“源码”和“工具”进行深入解析。 首先,我们需要了解什么是IP地址。IP地址(Internet Protocol Address)是互联网上每个设备的唯一标识,它允许...