收藏 分享(赏)

Java EE面向对象实战之道.doc

上传人:dzzj200808 文档编号:2994483 上传时间:2018-10-01 格式:DOC 页数:9 大小:49KB
下载 相关 举报
Java EE面向对象实战之道.doc_第1页
第1页 / 共9页
Java EE面向对象实战之道.doc_第2页
第2页 / 共9页
Java EE面向对象实战之道.doc_第3页
第3页 / 共9页
Java EE面向对象实战之道.doc_第4页
第4页 / 共9页
Java EE面向对象实战之道.doc_第5页
第5页 / 共9页
点击查看更多>>
资源描述

1、http:/ EE/J2EE 面向对象实战之道OO 思维经常看到不少人抱怨 Java EE/J2EE 中配置太复杂,烦琐,不简单易学,其实所谓简单易学是取决于你是否有 OO 思维方式。分层架构是面向对象 OO 在企业软件中应用的标志,目前一个企业软件系统包括表现层、业务层和持久层,那么分层架构和 OO 关系是如何?表现层的界面表单中通常是一些离散数据,也就是单个字段数据,通过Struts 等框架提供 ActionForm 以及标签库,将这些单个字段数据封装起来和业务层的 Domain Model 进行了映射,因此,表现层的主要编程工作就是映射配置。持久层是将 Domain Model 对象保存

2、到数据库中,过去使用 JDBC,我们要逐个打开这些 Model 对象,然后每个字段逐个 保存到数据库中,如果说表现层框架是实现离散数据封装,那么持久层实现的是反方向:拆封。Hibernate 是一个持久层 O/R mapping 框架, 也就是在对象和关系数据库之间进行映射的框架,EJB 的 CMP 也是类似道理,因此,持久层的主要编程工作也是映射配置。表现层和持久层这种配置工作就如同打包邮寄一样:你首先要将你的单件用一个箱子包装起来,达到目的地,这个箱子被打开,单件被逐步取出。表现层和持久层这样做的目的是保证中间业务层完全面向对象,保证业务层完全是和一个个对象模型打交道。在一个真正面向对象的

3、系统中,表现层和持久层是为了将非对象化的数据转为对象。因此,在先进的 JavaEE/J2EE 架构中,表现层和持久层的主要工作就是配置工作,而且主要是映射 mapping 的配置。下面的问题就是:如何解决映射配置简单而且易用,如果拥有正确的指导配置的思维,那么配置工作就容易简单多, 否则,就倍感配置复杂。 那些感觉 Java 配置复杂的人其实他并没有完整的 OO 思维。为什么这么说呢?以ORM(Hibernate)配置简易方式说明:配置的简要之道首先,配置是映射 XML 配置,顾名思义,也就是在两者之间做协调,牵线搭桥,说白了,就是做红娘,但和做红娘又有些区别,做红娘可以要求双方做些改变,互相

4、迁就,但是做映射配置,则不能这样,因为那样做就可能做出和需求要求不一样的东西。配置的简要之道就是:围绕对象模型进行配置;而不是围绕数据表进行配置。以持久层映射配置来说:存在 Domain Model 对象和关系数据表,如果感觉在两者之间配置映射很困难,双方做些改变,但是有可能 需求不答应,你一旦为协调而作出的改变可能偏离需求实现的目标,最后作出的系统面貌全非,根本不是客户所需要的。那么怎么办?很显然,紧扣需求,反映需求的那一方坚决不要变动,那么Domain Model 和关系数据表哪一方反映需求呢?按照 OO 分析,当然 是 Domain Model,Model 对象我们是依据 Evans M

5、odel 等模型驱动设计 MDD 概念设计出来,他们是需求的代表。很显然,我们的映射配置必须顺着 Model 对象这个思维来配,对于名词式的 Model,关联无外乎是其主要关系,当然还有继承,因此,象 Hibernate 这些映射配置语法也是面向这些主要对象关系的。表现层配置也是同样的道理,需要将 Domain Model 配置成界面表单,在实际中,我们有可能采取的是通过界面收集需求,因此,这个映射配置过程也是考验 Model 对象是否提炼正确与否,有可能发现 Model 不能实现一些界面需求功能,这时反过来必须修改我们的 Model,而不是仅仅在表现层这个技术层面做些补救措施就糊弄过去。Ja

6、va EE/J2EE 系统开发过程 敏捷的迭代是必然的。没有一个天才能够一步到位提炼出兼顾界面和数据表以及需求的统一模型出来。总之,完成一个真正面向对象的 Java EE/J2EE 系统,必须抓住领域建模和具体框架熟练配置两点,只有这样才能保证 Java 项目成功实施。最关键的是提炼出反映出业务系统的领域模型:Domain Model,完成业务建模后,就是依赖Struts/Hibernate 等配置分配将 Model 映射到界面和数据库,其实就是将业务模型移植到计算机领域并能够正确运行。 高聚合和低关联如果一个系统都被设计成相互没有任何不包含的单个对象,很显然是不能正确反映实际需求的,万事万物

7、都是有其部分组成的,例如窗户由玻璃和框架组成,人是由胳膊 腿等身体部分组成,现实世界中,事物之间总是存在关系,聚合和组成是最常见的。例如订单,一个订单 Orders 中由客户名称和地址,订购的产品品种和数量,客户名称和地址我们可以抽象为 Customer 来代表,产品我们使用 Product 来代表,由于一个订单中可能订购了多个产品,很显然,一个订单对象中应该有多个 Product 对象,而且每个 Product 的数量不一样,我们将 Product 和其数量再抽象包装成 OrderLine 订单条目对象,这样,订单中包含多个订单条目,而且订单条目只有依赖某个订单,是其组成部分,是一种强聚合关

8、系,不是普通的聚合或关联关系。而 Customer 和 Order 之间是一种聚合关系,如果订单没有客户信息,就不成为订单了。下面再以用户 User 这个对象为例,用户 User 可能拥有很多动态属性,一些属性需要运行时动态确定,用户和动态属性是一个整体和部分的聚合关系;每个用户都必然属于某个部门,因此,用户和部门属性对象之间也是一个整体和部分的聚合关系,这两种聚合关系不同之处在于:前者一个用户可能有多个动态属性,是 1:N 关系;部门 Dept 和用户 User 之间是 1:N 关系,一个部门中可能有多个用户,反过来说,对于用户 User 来说:它和部门 Dept 之间是 N:1关系。通过以

9、上建模过程,我们基本搞清楚两件事:这个领域中存在哪些模型对象?按照 Evans 的 DDD 理论,哪些是实体,哪些是值对象;然后我们必须搞清楚那些聚合关系,他们是整体部分的关系,用来共同组成一个完整对象的。持久层 Hibernate 聚合实现在持久层我们需要做的主要工作就是将上述 Domain Model 进行持久化映射配置,以 User 为例,User 是一个实体,我们配置 User.hbm.xml 如下:在 User 的映射配置文件中,我们很自然地表达了上节 Model 之间的聚合关系,通过 Hibernate 配置,我们将模型对象之间的关系可以持久化保存到数据库中了,也就是可以永久维持这

10、种关系,实际上,现实世界中也是这样的,部分和整体的关系是一直存在,除非这个整体这个对象不存在,而且修改部分对象内部值,必须通过整体这个对象。在 user 配置中,我们并没有去做任何关系数据表 testuser 的设计和设定,因为我们知道,当 User.hbm.xml 配置完成后,这个 J2EE 系统部署发布到 J2EE容器中时,Hibernate 会根据这个配置自动创建数据表 testuser,数据表的建立已经是一个部署调试阶段的、技术层面的具体工作。Hibernate 重要的父子关系Hibernate 在处理 User 和 UserProperty 这样一对多的父子关系时,具体实现起来要有一

11、些具体细节必须注意,而且 Hibernate2 和 Hibernate3 两个版本是不一样的:当我们需要只通过一句话 session.save(user)或 session.update(user)就能完成 User 和它其中多个 Userproperty 都能自动保存或更新时(必须指定cascade=“all“ 或 save-update),尤其是 update(user)更新时,其子集合userProps 属性中可能有一些 Userproperty 是修改过的,一些 Userproperty则是新增的,对于新增要使用 insert 语句;而对于修改则使用 update 语句,当我们笼统地调

12、用一句 update(user)时,那么 Hibernate 是如何判断这个 user中子集合中哪些是修改?哪些是新增的?Hibernate 是通过主键来判断的,也就是说,通过 UserProperty 的主键来判断该对象是修改?还是新增。最关键的是:这个主键必须由 Hibernate 自动产生,如果你想自己指定子对象 UserProperty 主键,那么就有可能很多麻烦,这个麻烦是出其的麻烦,无法判断具体原因。所以,在简单方便的道路上迈错一步就是万丈深渊。下面是 UserProperty 的映射配置:注意:以上配置只适合 Hibernate 3.0 以上版本,如果是 Hibernate 2,

13、那么必须在 :中加入 unsaved-value=“null“,而且这个值是 null 还是 0 或-1,取决你的主键类型:是不是感觉 Hibernate2 太麻烦了!在 Hibernate3 中,就没有这个规定了,所以,如果当初使用 Hibernate2 来实现 J2EE 的 oo 简洁实现之道,还存在技术上的困难和难点。Hibernate2 和 Hibernate3 在处理父子关系上,还有一个不同就是 lazy 设定上:Hibernat2 缺省 lazy 是 false,当通过 load 将 User 获取以后,在session 关闭以后,你可以直接通过 user.getUserProps

14、()方法获得其中子集合;而 Hibernate3 则不行了,缺省 lazy 是 true,在 session 关闭情况下,只有两种方式获得子集合:1. Open session in view,也就是在表现层一直打开持久层的 session,这不但违背分层不干扰原则,而且造成数据库连接一直打开,一旦出错,有可能造成内存泄漏死机等问题。2.在 load 父对象 User 时,调用Hibernate.initialize(user.getUserProps();强行装载所有的子对象,这样问题是:我们再也无法通过简单一句 load 生成父对象 User 及其所有内部部分,而无须照顾其内部关系。板桥实

15、践中总结方法是:根据当初 EJB CMP 的读取模式,采取 JDBC 来读取整个 User 及其部分子集合,缺点也是必须在 Dao 语句中打开 User(破坏封装),根据其内部结构从数据库中获取数据,这样的好处是:我们可以使用统一的Hibernate 模板来进行任何一个模型的持久化(不必为每个模型写一套 DAO 实现类),而无须关心其内部结构了。注意:Spring+Hibernate 采取的是 Open session in view 方案,这也是这种架构在系统复杂时发生性能问题一个原因,J 道性能板块有多个这样的求救贴。使用 Hibernate 映射配置另外一个注意点就是:使用双向关系可以提

16、高性能,但是 Evans DDD 告诉我们,建模时尽量搞 单向关系,不要用双向,这两者有矛盾之处,实际中,我们如果使用 Hibernate 作为持久层框架,那么就采取双向,性能很重要啊,否则后果很严重,这种设计和性能不匹配也是目前面向对象领域需要解决的另外一个问题。通过在子对象 UserPropery 配置中引入 many-to-one ,然后在父对象 User配置中规定 inverse=“true“ 来实现双向,Hibernate 会通过和 insert 或update 一条 SQL 语句完成关系设定。表现层 Struts 聚合实现前面我们完成了 Hibernate 的映射配置,下面是表现层

17、的映射配置,这是使用标签库来实现,我们使用 Struts 的标签库来实现:在界面主要实现下图效果:当进行用户 User 资料增删改查时,需要一个如图录入页面,部门是通过下来菜单选择,用户属性 UserPropery 是通过一行行属性名称和属性值输入的,主要是在 user.jsp 中完成:UserId:Username:属性 Id属性名称属性值相应的 UserActionForm 和 User Model 内容差不多,不同之处:为接受多个动态属性的输入,需要设定一个特定的方法:public class UserForm extends ModelForm . public UserPropert

18、y getUserProp(int index) return (UserProperty)(List)userProps).get(index);. 增删改查和批量查询根据 JdonFramework 的简化可迅速配置实现,这里不再描述,整个项目的代码结果如下图:也就是 10 个类左右,而且都是和业务有关,简要,扣主题,整个案例代码是免费自由下载, 作为 JdonFramework 应用源码下载之一的 sample。总结一个真正面向对象的 JavaEE 或 J2EE 系统,应该是一个围绕领域模型的多层架构,以面向对象 OO 思维进行领域模型提炼和重构,继续以 OO 思维进行表现层和持久层的配置实现,才能寻找到一条 Java 系统快速有效高质量的解决之道。相关文章:面向对象与领域建模 当前 Java 项目开发中几种认识误区 实战 DDD(Domain-Driven Design 领域驱动设计)领域模型驱动设计(DDD)之模型提炼 数据库时代的终结更多 OO 思维专题

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 专业基础教材

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报