??xml version="1.0" encoding="utf-8" standalone="yes"?>
cMcM间的关系对于理解面向对象h很重要的作用Q以前在面试的时候也l常被问到这个问题,在这里我׃l一下?br />cMcM间存在以下关p?
(1)泛化(Generalization)
(2)兌(Association)
(3)依赖(Dependency)
(4)聚合(Aggregation)
UML图与应用代码例子:
1.泛化(Generalization)
[泛化]
表示cMcM间的l承关系Q接口与接口之间的承关p,或类Ҏ口的实现关系。一般化的关pL从子cL向父cȝQ与l承或实现的Ҏ相反?br />[具体表现]
父类 父类实例Qnew 子类()
[UML图](?.1)
?.1AnimalcMTigerc?Dogcȝ泛化关系
[代码表现]
?.2 PersoncMScrewdrivercȝ依赖关系
[代码表现]
java代码: |
public class Item implementsSerializable{ privateLong id = null; privateint version; privateString name; private User seller; privateString description; private MonetaryAmount initialPrice; private MonetaryAmount reservePrice; privateDate startDate; privateDate endDate; privateSet categorizedItems = newHashSet(); privateCollection bids = newArrayList(); private Bid successfulBid; private ItemState state; private User approvedBy; privateDate approvalDatetime; privateDate created = newDate(); // getter/setterҎ省略不写Q避免篇q太?/span> } |
java代码: |
public interface ItemDao { public Item getItemById(Long id); publicCollection findAll(); publicvoid updateItem(Item item); } |
java代码: |
public class ItemDaoHibernateImpl implements ItemDao extends HibernateDaoSupport { public Item getItemById(Long id){ return(Item) getHibernateTemplate().load(Item.class, id); } publicCollection findAll(){ return(List) getHibernateTemplate().find("from Item"); } publicvoid updateItem(Item item){ getHibernateTemplate().update(item); } } |
java代码: |
public class ItemManager { private ItemDao itemDao; publicvoid setItemDao(ItemDao itemDao){ this.itemDao = itemDao;} public Bid loadItemById(Long id){ itemDao.loadItemById(id); } publicCollection 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(newDate())) 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完成持久化操?/span> return newBid; } } |
java代码: |
publicclass Item implementsSerializable{ // 所有的属性和getter/setterҎ同上Q省?/span> 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(newDate())) 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); // h意这一句,透明的进行了持久化,但是不能在这里调用ItemDaoQItem不能对ItemDao产生依赖Q?/span> return newBid; } } |
java代码: |
publicclass ItemManager { private ItemDao itemDao; publicvoid setItemDao(ItemDao itemDao){ this.itemDao = itemDao;} public Bid loadItemById(Long id){ itemDao.loadItemById(id); } publicCollection 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); // 必须昑ּ的调用DAOQ保持持久化 } } |
java代码: |
publicclass Item implementsSerializable{ // 所有的属性和getter/setterҎ都省?/span> privatestatic ItemDao itemDao; publicvoid setItemDao(ItemDao itemDao){this.itemDao = itemDao;} publicstatic Item loadItemById(Long id){ return(Item) itemDao.loadItemById(id); } publicstaticCollection 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(newDate())) 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); // 调用DAOq行昑ּ持久?/span> return newBid; } } |
java代码: |
this.getBids().add(newBid); |
java代码: |
class Topic { boolean isAllowReply(){ Calendar dueDate = Calendar.getInstance(); dueDate.setTime(lastUpdatedTime); dueDate.add(Calendar.DATE, forum.timeToLive); Date now = newDate(); return now.after(dueDate.getTime()); } } |
用例名称Q网站公告发?/td> |
用例标识P202 |
参与者:负责?/td> |
要说明: 负责人用来填写和修改家教|站首页的公告,公告最l显C在家教|站的首上?/td> |
前置条gQ?br /> 负责人已l登陆家教网站管理系l?/td> |
基本事g: 1Q?负责人鼠标点几Z修改公告”按?br /> 2Q?pȝ出现一个文本框Q显C着原来的公告内?br /> 3Q?负责人可以在文本框上修改公告Q也可以完全删除Q重新写新的公告 4Q?负责人编辑完文本框,按“提交”按钮,首页公告p修改 5Q?用例l止 |
其他事gA1Q?br /> 在按“提交”按钮之前,负责人随时可以按“返回”按钮,文本框的M修改内容都不会媄响网站首늚公告 |
异常事g: 1Q?提示错误信息Q负责h认 2Q?q回到管理系l主面 |
后置条gQ?br /> |站首页的公告信息被修改 |
注释Q无 |
UMLl一建模语言
UMLQUnified Modeling LanguageQ统一建模语言Q是一U面向对象的建模语言Q它的主要作用是帮助我们对Y件系l进行面向对象的描述和徏模,它可以描q这个Y件开发过E从需求分析直到实现和试的全q程。UML通过建立各种cR类之间的关联、类/对象怎样怺配合实现pȝ的动态行为等成分Q这些都UCؓ模型元素Q来l徏整个模型Q刻d观世界。UML提供了各U图形,比如Use Case图、类图、顺序图、协作图、状态图{,来把q些模型元素及其关系可视化,让h们可以清楚容易的理解模型。我们可以从多个视角来考察模型Q从而更加全面的了解模型Q这样同一个模型元素可能会出现在多个图中,对应多个囑Ş元素?
p图viewQ图diagramQ模型元素model element和通用机制general mechanism{几个部分组?.视图是表辄l的某一斚w特征的UML建模元素的子集,由多个图构成Q是在某一个抽象层上,对系l的抽象表示.图是模型元素集的囑Ş表示Q通常为弧Q关p)和顶点(其他模型元素Q相互连接构成的.模型元素代表面向对象中的cR对象、消息和关系{概念,是构成图的最基本的常用概?通用机制用于表示其它信息Q比如注释、模型元素的语义{。另外,它还提供扩展机制QUML语言能够适应一个特D的ҎQ或q程Q,或扩充至一个组l或用户.
UML是用来描q模型的Q用模型来描q系l的l构或静态特征,以及行ؓ或动态特征。从不同的视角ؓpȝ的构架徏模,形成pȝ的不同视图(VIEWQ?
用例视图(use case view)Q强调从用户的角度看到的或需要的pȝ功能Q是被称为参与者的外部用户所能观察到的系l功能的模型图;
逻辑视图(logical view)Q展现系l的静态或l构l成及特征,也称为结构模型视?structural model view)或静态视图(static viewQ;
q发视图(concurrent view)Q体Cpȝ的动态或行ؓ特征Q也UCؓ行ؓ模型视图Qbehavioral model viewQ、动态视?dynamic view)Q?
lg视图(component view)Q体Cpȝ实现的结构和行ؓ特征Q也UCؓ实现模型视图(implementation model view) Q?
配置视图(deployment view)Q体Cpȝ实现环境的结构和行ؓ特征Q也UCؓ环境模型视图Qenvironment model viewQ或物理视图(physical view)?
建模工具Rose 之游
ROSE是美国Rational公司的面向对象徏模工P利用q个工具Q我们可以徏立用UML描述的Y件系l的模型Q而且可以自动生成和维护C++、Java、VB、Oracle{语a和系l的代码?
ROSE是个菜单驱动应用E序Q用工具栏帮助用常用特性。它的界面分Z个部?-BrowserH口、DiagramH口和DocumentH口。BrowserH口用来览、创建、删除和修改模型中的模型元素QDiagramH口用来昄和创作模型的各种图;而DocumentH口则是用来昄和书写各个模型元素的文档注释?
Rose界面
Rose模型的四个视图是Use Case视图 、Logical视图、Component视图和Deployment视图。每个视N对不同对象,h不同用途。Use Case视图包括pȝ中的所有角艌Ӏ案例和Use Case图,q包括一些Sequence囑֒Collaboration图?
Use Case视图
Logical视图xpȝ如何实现使用案例中提到的功能。它提供pȝ的详l图形,描述lg间如何关联。除其它内容之外QLogical视图q包括需要的特定cRClass囑֒State Transition 图。利用这些细节元素,开发h员可以构造系l的详细设计?
Logical视图
Component视图包括模型代码库、执行库和其它组件的信息。组件是代码的实际模块。Component视图的主要用h负责控制代码和编译部|应用程序的人。有些组件是代码库,有些lg是运行组Ӟ如执行文件或动态链接库QDLLQ文件?
Collaboration囑օ注系l的部vQ可能与pȝ的逻辑l构不同。整个小l都用Collaboration图了解系l部|Ԍ但用h发布应用E序的h员?
Rose的九U图
用例图use case diagramQ描q系l功?
cdclass diagramQ描q系l的静态结?
对象图object diagramQ描q系l在某个时刻的静态结?
序列图sequence diagramQ按旉序描述pȝ元素间的交互
协作图Collaboration diagramQ按照时间和I间序描述pȝ元素间的交互和它们之间的关系
状态图state diagramQ描qCpȝ元素的状态条件和响应
zd图activity diagramQ描qCpȝ元素的活?
lg图component diagramQ描qC实现pȝ的元素的l织
配置图deployment diagramQ描qC环境元素的配|,q把实现pȝ的元素映到配置?
Ҏ它们在不同架构视囄应用Q可以把9U图分成Q?
用户模型视图Q用例图
l构模型视图Q类图、对象图
行ؓ模型视图Q序列图、协作图、状态图、活动图Q动态图Q?
实现模型视图Q组件图
环境模型视图Q配|图
?/SPAN>UML?/SPAN>use caseg最單的,用例建模的最主要功能是用来表达pȝ的功能性需求或行ؓQ依我的理解用例建模可分为用例图和用例描q。用例图由参与者(ActorQ、用例(Use CaseQ、系l边界、箭头组成,用画囄Ҏ来完成。用例描q用来详l描q用例图中每个用例,用文本文档来完成Q以及由头所l成的各U关p,包括泛化Q包含,扩展{。本文准备向大家介绍以下内容,所有图C均?/SPAN>PowerDesigner所?/SPAN>.
u 用况
u 参与?/SPAN>
u 泛化
u <<use>>
u <<include>>
u <<extend>>
u 用例描述
Q. 用况Q?/SPAN>use caseQ?/SPAN> 图1 用况?/SPAN>
是对一l动作序列(其中包括它的变体Q的描述Q系l执行该动作为执行此动作的参与者生一个可观察的结果倹{比如你使用计算器,q里可以把计器看作为用况,参与者是dQ登峰按了3Q3Q用冉|行的序列Q,计算机器q回一个结果6?/SPAN>
Q. 参与?/SPAN>(Actor)
参与者不是特指hQ是指系l以外的Q在使用pȝ或与pȝ交互中所扮演的角艌Ӏ因此参与者可以是人,可以是事物,也可以是旉或其他系l等{。还有一点要注意的是Q参与者不是指人或事物本nQ而是表示人或事物当时所扮演的角艌Ӏ比如小明是图书馆的理员,他参与图书馆理pȝ的交互,q时他既可以作ؓ理员这个角色参与管理,也可以作为借书者向图书馆借书Q在q里明扮演了两个角Ԍ是两个不同的参与者。参与者在d中用Wh物画来表C,人物下面附上参与者的名称?/SPAN> Q. 泛化
泛化和类中的泛化概念是一LQ子用况l承父用늚行ؓ和含义,q可以增加或覆盖父用늚行ؓ;子用况可以出现在M父用况出现的位置Q父和子均有具体的实例)。下面给ZU图C来说明泛化的概念和含义
图2 含义l承 图3 行ؓl承
Q.<<user>>
<<use>>: ?/SPAN>关系非常象一个函数调用或一个子q程以这U方式用的用例UCؓ?
象用例因为它不能单独存在而必被其它用例使用Q请看下?
图4 使用<<use>>CZ
Q.<<include>>
怎么解释q个定义呢? q是说明一下它的功能吧Q?/SPAN><<include>>可以把几个用例的公共步骤分离出来成ؓ一个单独的被包含用例。学q?/SPAN>C的朋友知道它的含义了吧。呵?/SPAN>
好的Q定义都已经知道了,下面用一个示例来加深大家的印象。假如有个h事系l,l理可以查看员工的信息,q可以增加,修改和删除,但每ơ执行这三个操作Ӟ都要定位到相应的员工Q即先查询定位到要操作的员工。图Q给Zq种表述?/SPAN>use case ?/SPAN>,L?/SPAN><<include>>的含?/SPAN>
图5 <<include>>的用?/SPAN>
6Q?/SPAN><<extend>>
<<extend>>为已存在用例d新的行ؓ提供了一U方法?/SPAN> 基础用例提供了一l扩展点Q?/SPAN>extend pointsQ,扩展Ҏ钩子Q在此可以添加新的行为,扩展用例提供了一l插入片D,q些片段可被插入到基用例的钩子位|。需要注意的是基用例不知道扩展用例的Ml节Q它仅ؓ扩展用例提供了钩子。这?/SPAN><<include>>不同Q此时如果没有被包含用例Q客L例将不完整。图Q说明了主述文字描述
图6 <<extend>>的用?/SPAN>
Q.用例描述
当然用例描述是对用例的文字性说明。具体要描述哪些,q里׃多说了,l大家一个具体示例一看就明白。假如有个家教网Q下面只是一个抽象片Dc主要是Z说明用例描述的含义?/SPAN>
下面是用例|站公告发布的用例描q?/SPAN>
Z么要写有兛_?关系数据库之间的映射的文章呢Q因为在对象范例和关p范例之间“阻抗不匚w”。对象范例基于Y件工E的一些原理,例如耦合、聚合和装Q而关p范例则Z数学原理Q特别是集合论的原理。两U不同的理论基础D各自有不同的优缺炏V而且Q对象范例侧重于从包含数据和行ؓ的对象中构徏应用E序Q而关p范例则主要针对数据的存储。当问而寻找一U合适的ҎӞ“阻抗不匚w”就成了主要矛盾Q用对象范例,您是通过它们的关pL讉K对象Q而用关p范例,则通过复制数据来联接表中的行。这U基本的差异D两种范例的结合ƈ不理惻I不过话说回来Q本来就预料C有一些问题。对象-关系数据库之间的映射成功的一个秘诀是理解q两U范例和它们的差异,然后Zq些认识来进行明智的取舍?/P>
本文应该能够消除C开发周期中一些普遍共有的误解Q对对象-关系数据库之间映所涉及到的一些问题提供了切合实际的看法。这些策略基于我的开发经验,目范围从小到大Q涉及金融、销售、军事、远E通信和外购等行业。我已对使用 C++?Smalltalk、Visual Basic ?Java 语言~写的应用程序应用了q些原则?/P>
如何对象映成关系数据?/STRONG> 属性映成?/STRONG> 在关pL据库中实现?/STRONG> 类映射成表 整个cdơ结构用一个数据实?/B> q种Ҏ的优Ҏ单,因ؓ所需的所有h员数据都可以在一张表中找刎ͼ所以在Z更改角色时支持多态性,q且使用q种ҎQ专门报告(Z组用户特定目的所执行的报告,q些用户通常自己写报告)也非常简单。缺Ҏ每次在类层次l构的Q何地Ҏ加一个新属性时都必d一个新属性添加到表中。这增加了类层次l构中的耦合 - 如果在添加一个属性时有Q何错误,除获得新属性的cȝ子类外,q可能媄响到层次l构中的所有类。它q可能浪Ҏ据库中的许多I间。我q必L? 每个具体cM用一个数据实?/B> q种Ҏ最大的好处是,它仍然能相当Ҏ地执行专门报告,只要您所需的有兛_一cȝ所有数据都只存储在一张表中。但也有几个~点。一个是当修改类Ӟ必须修改它的表和它所有子cȝ表。例如,如果要向 每个cM用一个数据实?/B> q种Ҏ的最大好处就是它能够最好地适应面向对象的概c它能够很好地支持多态性,对于对象可能有的每个角色Q只需要在相应的表中保存记录。修改超cdd新的子类也非常容易,因ؓ您只需要修Ҏd一张表。这U方法也有几个缺炏V第一Q数据库中有大量的表 -- 实际上每c都有一个(加上l护关系的表Q。第二,使用q种技术读取和写入数据的时间比较长Q因为您必须讉K多个表。如果通过类层次l构中的每个表放入不同物理磁盘驱动器盘片Q假设每个磁盘驱动器头都单独操作)上来地组l数据库的话Q就可以~解q个问题。第三,有关数据库的专门报告很困难,除非d一些视图来模拟所需的表?/P>
比较映射{略 ?6 昄了一个更新过的持久性模型,用于整个类层次l构映射成一个数据实体。尽很明显Q数据库中的I间费增加了,但请注意Q按照这U策略操作,只需花非常小的代价就可以更新模型?/P>
?7 昄了将每个具体cL成数据实体时的持久性模型。用这个策略,虽然因ؓ我们从教授提升到ln教授Q这样对象和我们的关pd有了改变Q学生变成教授)Q所以如何处理对象的q个问题更复杂了Q但我只需要添加一个新表?/P>
?7. 扩展的层次l构的具体类映射成数据实?/STRONG> ?8 昄了第三种映射{略的解x?-- 单个类映射成单个数据实体。这需要我d一个只包括 ?8. 扩展的层次l构的所有类映射成数据实?/STRONG> 要摒弃这样一U观点,卌些办法都不够好;每种办法都有其优~点。在下面的表 1 中对它们q行比较?/P>
?1. 比较映射l承的各U办?/B> 映射兌、聚合和l成 兌、聚合和l合之间的差?/STRONG> 在图 9 中有三个c,其中两个在它们之间有单的兌关系Q有两个׃n聚合关系Q实际上Q组合可能是q种模型中更切的说法)。(有关关系的详l信息,请参?A Building Object Applications That Work"。)从数据库的观点看Q聚合/l合和关联是不同的,在聚合情况下Q在整体中读取时Q您通常希望在部分中dQ而在兌情况下,需要执行什么操作ƈ不L那么明显。在对象保存到数据库中或从数据库中删除对象也存在相同的情况。当Ӟ上述讨论通常特定于商业领域,但这U经验之谈往往在很多情况下出现?/P>
在关pL据库中实现关p?/STRONG> 在图 10 中有三张表,它们的键 (OID) 和外键用于在它们之间实现关系。首先,? 实现多对多关?/STRONG> 看一下图 11 中应用程序的复合度。规则是Q一旦引入了兌表,复合度就“交叉”,如图 12 所C。gؓ '1' 的复合度d外边~引入,如图 11 ?12 中所C,以保留原始关联的整体复合度。原始的兌表明雇员有一U或多种利Qƈ且Q何给定的利都给予一个或多个雇员。在?11 中您可以看到Q即使在有关联表l护兌的情况下仍然是这U情c?/P>
有必要注明我选择应用构造型?lt;<兌?gt;>”而不是关联类的说?-- 关联类与它所描述的关联连接的虚线?-- Z两个原因。首先,兌表的目的是实现关联,而关联类的目的是描述兌。其ơ,?11 中采取的Ҏ反映了ؓ使用关系技术所需的实际实现策略?/P>
l束
在这一节中Q我会描qC些将对象成功映射成关pL据库所需的基本技术?/P>
cd性将映射成关pL据库中的零或几列。要CQƈ不是所有属性都是持久的。例如, cM?
属性,q个属性由其实例在计算时用,但它不保存到数据库中。而且Q某些对象属性本w就是对象,例如
对象有一个作为属性的
实例Q它映射为数据库中的几列Q实际上Q很有可?
cLw就映成一个或多个表)。重要的是,q是一个递归定义Q有时属性将映射成零或者多列。也有可能将几个属性映成表中的单一列。例如,代表国邮递区号代码的cd以有三个数字属性,每个都表C完整邮政编号代码中的每一部分Q而邮政编号代码可以在地址表中作ؓ单一的列存储?/P>
在将对象保存到关pL据库中时Q承的概念中发生几个有的问题。(请参?A Building Object Applications That Work"。)问题从根本上归结释如何在您的持久模型中组l承的属性。解册个难题所用的Ҏ会对pȝ设计有很大媄响。将l承映射到关pL据库中有三种基本解决办法Qؓ更好地理解它们,我将讨论在图 1 中显C的映射cd表的优缺炏Vؓ化问题,我没有ؓcȝ所有属性都建模Q也没有为其完整{或Q何类Ҏ建模?/P>
cd表的映射通常不是直接的。除了非常简单的数据库以外,您不会有cd表的一对一映射。在以下章节中,我将讨论为关pL据库实现l承l构的三U策略:
使用q种ҎQ您可以一个完整类层次l构映射成一个数据实体,而层ơ结构中所有类的所有属性都存储在这个实体中。图 2 描述了采取这个方法时?1 的类层次l构的持久模型。请注意Qؓ表的主键引入了一? ?- 我在所有解x案中都?OID Q没有商业含义的标识Q又U替代键Q,只是Z保持一致和使用我所知道的向数据实体分配键的最好办法?/P>
列来表明行代表的是学生、教授还是其它类型的人员。在Zh单一角色时这U方法很有效Q但如果他们有多个角Ԍ例如Q一个h既是学生又是教授Q,很快׃失效?/P>
使用q种ҎQ每个数据实体就既包含属性又包含它所表示的类l承的属性。图 3 描述了采取这个方法时?1 的类层次l构的持久模型。有? cd应的和与
cd应的数据实体Q因为它们是具体c,但没有与
cd应的数据实体Q因为它是抽象类Q它的名UC斜体字表C)。ؓ每个数据实体都分别分配了自己的主键,
?
?/P>
cL加高度和重量Q就需要同时更C个表Q它会涉及很多工作。第二,无论何时Q只要对象更改了它的角色 - 可能您聘用了您一个刚毕业的学生作为教?- 则需要将数据复制到相应的表中Qƈ为它指定一个新?OID。这又涉及到很多工作。第三,很难在支持多个角色的同时仍维护数据完整性。(q种情况是可能的Q只是比原先困难一炏V)例如Q您会在哪里存储既是学生又是教授的h的姓名呢Q?/P>
使用q种ҎQؓ每个cdZ张表Q它的属性是 OID 和特定于该类的属性。图 4 描述了采取这个方法时?1 的类层次l构的持久模型?h意,? 用作了所有三个数据实体的主键。图 4 的一个有的Ҏ是Qؓ
?
中的
列都分配了两个构造型Q而这在标准徏模语a (UML) 中是不允许的。我的意见是Q这是一个必ȝ UML 持久性徏模概要解决的问题Q甚臛_能在q个建模规则中也需要更攏V(有关持久性模型的详细信息Q请参阅
现在Q请注意Q每个映策略怎样产生不同的模型。要理解三种{略之间的设计优~点Q请考虑?5 中显C的Ҏ们的cdơ结构做些简单的更改Q添加了 Q这是从
中承的?/P>
cȝ新属性的新表。这U方法的~点是,要用新cȝ实例Q它需要好几个数据库访问?/P>
专门报告
实现的难易程?/FONT>
数据讉K的难易程?/FONT>
耦合
数据讉K速度
对多态性的支持
不仅必须对象映到数据库中Q还必须对象之间的关系q行映射Q这h能在以后q行恢复。对象之间有四种cd的关p:l承、关联、聚合和l成。要有效地映这些关p,必须理解它们之间的差异、如何实C般的关系Q以及如何实现特定的多对多关pR?/P>
从数据库的角度看Q关联和聚合Q组合关pM间的唯一不同是对象相互之间的l定E度。对于聚合和l合Q在数据库中Ҏ体所做的操作通常需要同时对部分q行操作Q而关联就不是q样?/P>
关系数据库中的关pL通过使用外键来维护的。外键是在一张表中出现的一个或多个数据属性;它可以是另一张表的键的一部分Q或者干脆碰巧就是另一张表的键。外键可以让您将一张表中的一行与另一张表中的一行相兌v来。要实现一对一和一对多的关p,您只需要将一张表的键包括在另一张表中?/P>
?
数据实体间有一个一对一的关联。一对一兌是它的每个复合度的最大值都?1 的这么一U关pR要实现q个关系Q我?
数据实体中用属?
Q?CODE> 数据实体的键。因为关联是单向?-- employee 那些行知道它们的位置行,但反q来׃?-- 所以我必须q么做。如果这是个双向的关联,我还会在
中添加一个名?
的外键。然后,使用相同的方法在
?
之间实现了多对一兌Q又UCؓ一对多兌Q,唯一的不同是外键放在了
中,因ؓ它在关系的“多”方?/P>
要实现多对多关系Q需要关联表的概念,它是一U数据实体,唯一目标是在关系数据库中l护两个或多个表之间的关联。图 10 中,?CODE> ? 之间有一个多对多关系。图 11 中,可以看到如何使用兌表来实现多对多关pR在关系数据库中Q关联表中包含的属性传l上是关pM涉及到的表中的键l合。关联表的名U通常是它所兌的表的名U组合,或者是它实现的兌的名U。在q种情况下,我选择
而不?
?
Q因为我觉得它可以更好地反映兌的性质?/P>
![]() |
1.2学习~译更好?DAO 的技?/SPAN> Sean C. Sullivan (dao-article@seansullivan.com) J2EE 开发h员用数据访问对?Data Access Object DAO)设计模式Q以便将低别的数据讉K逻辑与高U别的业务逻辑分离。实?DAO 模式涉及比编写数据访问代码更多的内容。在本文中,Java 开发h?Sean C. Sullivan 讨论?DAO ~程中三个常常被忽略的方面:事务界定、异常处理和日志记录?/FONT> 在过?18 个月中,我参加了一个由有才华的软g工程师组成的组Q构建定制的、基?Web 的供应链理应用E序。我们的应用E序讉K范围q泛的持久性数据,包括配送状态、供应链衡量(metrics)、库存、货q发、项目管理数据和用户信息。我们用 JDBC API q接到我们公司的不同数据库^CQƈ在整个应用程序中使用 DAO 设计模式?/FONT> ?1 昄了应用程序和数据源之间的关系Q?/FONT> 在整个应用程序中使用数据讉K对象(DAO)使我们可以将底层数据讉K逻辑与业务逻辑分离开来。我们构Z为每一个数据源提供 GRUD (创徏、读取、更新、删?操作?DAO cR?/FONT> 在本文中Q我ؓ您介l构建更好的 DAO cȝ DAO 实现{略和技术。更切地说Q我讨论日志、异常处理和事务界定。您学到如何将q三者结合到自己?DAO cM。本文假定您熟悉 JDBC API、SQL 和关pL据库~程?/FONT> 我们以?DAO 设计模式和数据访问对象的概述开始?/FONT> DAO 基础
具体?DAO cd含访问特定数据源的数据的逻辑。在下面一节中您将学习设计和实现数据访问对象的技术。有?DAO 设计模式的更多内容请参阅 参考资?/FONT>?/FONT> 事务界定 事务界定是定义事务边界的方式。J2EE 规范描述了两U事务界定的模型Q编E式(programmatic)和声明式(declarative)。表 1 分析了这两种模型Q?/FONT> ?1. 两种事务界定的模?/B>
我们侧重于~程式事务界定?/FONT> 设计考虑
了解上述问题的答案将有助于您选择最适合?DAO 的事务界定策略。在 DAO 中有两种主要的界定事务的{略。一U方式是?DAO 负责界定事务Q另一U将事务界定交给调用q个 DAO Ҏ的对象处理。如果选择了前一U方式,那么将事务代码嵌入?DAO 中。如果选择后一U方式,那么事务界定代码是?DAO cd面。我们将使用单的代码CZ帮助您更好理解每一U方式是如何工作的?/FONT> 清单 1 昄了一个有两种数据操作?DAOQ创建和更新Q?/FONT> 清单 1. DAO Ҏ
清单 2 昄了一个简单的事务。事务界定在 DAO cd面。注意在q个例子中调用者是如何在一个事务中l合多个 DAO 操作的?/FONT> 清单 2. 调用者管理的事务
q种事务界定{略对于需要在一个事务中讉K多个 DAO 的应用程序特别有用?/FONT> 可以?JDBC API 或?Java 事务 API(Java Transaction API JTA)实现事务界定?JDBC 事务界定?JTA 事务界定要简单,但是 JTA 提供了更多的灉|性。在下面一节中我将更深入地分析事务界定的机制?/FONT> ?JDBC q行事务界定
清单 3 昄了如何用 JDBC API 界定一个事务: 清单 3. ?JDBC API q行事务界定
使用 JDBC 事务界定Ӟ您可以将多个 SQL 语句l合C个事务中。JDBC 事务的一个缺Ҏ事务的范围局限于一个数据库q接。一?JDBC 事务不能跨越多个数据库。在下面Q我们将看一下如何用 JTA q行事务界定。因?JTA 不像 JDBC 那样有名Q所以我们首先做一个简介?/FONT> JTA ?/FONT> JTA 事务?JDBC 事务功能更强。JDBC 事务局限ؓ一个数据库q接Q?JTA 事务可以有多个参与者。所有下?Java q_lg都可以参?JTA 事务Q?/FONT>
使用 JTA 的事务界?/FONT>
当应用程序找C
当应用程序调?CODE> commit()Ӟ事务理器用一个两阶段的提交协议结束事务?/FONT> 控制事务?JTA Ҏ
应用E序调用 使用 JTA ?JDBC 您将需要用应用服务器的理工具讄 J2EE 应用E序?JNDI 查询数据源。一旦应用程序找C数据源对象,它就调用 XA q接与非 XA q接不同。一定要C XA q接参与?JTA 事务。这意味着 XA q接不支?JDBC 的自动提交功能。同Ӟ应用E序一定不要对 XA q接调用 选择最好的方式 在最q的许多目中,我们组是用 JDBC API q事务界定来构徏 DAO cȝ。这?DAO cd以ȝ如下Q?/FONT>
JDBC 事务q不L适合复杂的企业应用程序。如果您的事务要跨越多个 DAO 或者多个数据库Q那么下列实现策略也许更合适:
JDBC 方式׃其简单性而具有吸引力QJTA 方式提供了更大的灉|性。您所选择的实现将取决于应用程序的特定需求?/FONT> 日志记录?DAO 在本节,我将展示一个显C如何将 Jakarta Commons Logging 加入?DAO 中的代码CZ。在q之前,让我们回一下一些基本知识?/FONT> 选择日志?/FONT> ?2. Java q_的日志库
Jakarta Commons Logging 可以?CODE> java.util.logging 或?Jakarta Log4j 一同用。Commons Logging 是一个日志抽象层Q它隔离了应用程序与底层日志实现。?Commons LoggingQ您可以通过改变配置文g更换底层日志实现。Commons Logging ?Jakarta Struts 1.1 ?Jakarta HttpClient 2.0 中用?/FONT> 一个日志记录示?/FONT>
日志记录是所有Q务关键型应用E序的重要部分。如果在 DAO 中遇到故障,那么日志通常可以提供判断出错位置的最好信息。将日志加入?DAO 可以保证您有Zq行调试和故障排除?/FONT> DAO 中的异常处理 在实?DAO 模式Ӟ考虑以下问题Q?/FONT>
在?DAO 模式的过E中Q我们的组开发了一些处理异常的原则。遵从这些原则可以极大地改进您的 DAOQ?/FONT>
有关异常和异常处理技术的更多信息参阅参考资?/FONT>?/FONT> 实现实例Q?MovieDAO
DAO 模式的这个实现包含下面列出的cd接口Q?/FONT>
?3. MovieDAO 实现
MovieDAO 演示应用E序 q个 servlet 展示了如何将支持 JTA ?
要运行这个演C应用程序,需要在应用服务器上配置一?XA 数据源和一个非 XA 数据源。然后,部v daoexamples.ear 文g。这个应用程序可以在M兼容 J2EE 1.3 的应用服务器上运行。参?/FONT>参考资?/FONT>以获?EAR 文g和源代码?/FONT> l束?/FONT>
|