﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-享受JAVA-文章分类-分析与设计</title><link>http://www.blogjava.net/nighthawk/category/2519.html</link><description>享受JAVA，享受人生</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 12:56:46 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 12:56:46 GMT</pubDate><ttl>60</ttl><item><title>61条面向对象设计的经验原则</title><link>http://www.blogjava.net/nighthawk/articles/11261.html</link><dc:creator>nighthawk</dc:creator><author>nighthawk</author><pubDate>Fri, 26 Aug 2005 14:36:00 GMT</pubDate><guid>http://www.blogjava.net/nighthawk/articles/11261.html</guid><wfw:comment>http://www.blogjava.net/nighthawk/comments/11261.html</wfw:comment><comments>http://www.blogjava.net/nighthawk/articles/11261.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nighthawk/comments/commentRss/11261.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nighthawk/services/trackbacks/11261.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作者：Arthur J.Riel <BR><BR><SPAN class=content>“你不必严格遵守这些原则，违背它们也不会被处以宗教刑罚。但你应当把这些原则看成警铃，若违背了其中的一条，那么警铃就会响起。” </SPAN>
<P class=content>----------Arthur J.Riel<BR><BR>(1)所有数据都应该隐藏在所在的类的内部。</P>
<P class=content>(2)类的使用者必须依赖类的共有接口，但类不能依赖它的使用者。</P>
<P class=content>(3)尽量减少类的协议中的消息。</P>
<P class=content>(4)实现所有类都理解的最基本公有接口[例如，拷贝操作(深拷贝和浅拷贝)、相等性判断、正确输出内容、从ASCII描述解析等等]。</P>
<P class=content>(5)不要把实现细节(例如放置共用代码的私有函数)放到类的公有接口中。<BR>如果类的两个方法有一段公共代码，那么就可以创建一个防止这些公共代码的私有函数。 </P>
<P class=content>(6)不要以用户无法使用或不感兴趣的东西扰乱类的公有接口。</P>
<P class=content>(7)类之间应该零耦合，或者只有导出耦合关系。也即，一个类要么同另一个类毫无关系，要么只使用另一个类的公有接口中的操作。</P>
<P class=content>(8)类应该只表示一个关键抽象。<BR>包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包影响，则将对包中的所有类产生影响，而对其他的包不造成任何影响 . </P>
<P class=content>(9)把相关的数据和行为集中放置。<BR>设计者应当留意那些通过get之类操作从别的对象中获取数据的对象。这种类型的行为暗示着这条经验原则被违反了。 </P>
<P class=content>(10)把不相关的信息放在另一个类中(也即：互不沟通的行为)。<BR>朝着稳定的方向进行依赖. </P>
<P class=content>(11)确保你为之建模的抽象概念是类，而不只是对象扮演的角色。</P>
<P class=content>(12)在水平方向上尽可能统一地分布系统功能，也即：按照设计，顶层类应当统一地共享工作。</P>
<P class=content>(13)在你的系统中不要创建全能类/对象。对名字包含Driver、Manager、System、Susystem的类要特别多加小心。<BR>规划一个接口而不是实现一个接口。 </P>
<P class=content>(14)对公共接口中定义了大量访问方法的类多加小心。大量访问方法意味着相关数据和行为没有集中存放。</P>
<P class=content>(15)对包含太多互不沟通的行为的类多加小心。<BR>这个问题的另一表现是在你的应用程序中的类的公有接口中创建了很多的get和set函数。 </P>
<P class=content>(16)在由同用户界面交互的面向对象模型构成的应用程序中，模型不应该依赖于界面，界面则应当依赖于模型。</P>
<P class=content>(17)尽可能地按照现实世界建模(我们常常为了遵守系统功能分布原则、避免全能类原则以及集中放置相关数据和行为的原则而违背这条原则) 。</P>
<P class=content>(18)从你的设计中去除不需要的类。<BR>一般来说，我们会把这个类降级成一个属性。 </P>
<P class=content>(19)去除系统外的类。<BR>系统外的类的特点是，抽象地看它们只往系统领域发送消息但并不接受系统领域内其他类发出的消息。 </P>
<P class=content>(20)不要把操作变成类。质疑任何名字是动词或者派生自动词的类，特别是只有一个有意义行为的类。考虑一下那个有意义的行为是否应当迁移到已经存在或者尚未发现的某个类中。</P>
<P class=content>(21)我们在创建应用程序的分析模型时常常引入代理类。在设计阶段，我们常会发现很多代理没有用的，应当去除。</P>
<P class=content>(22)尽量减少类的协作者的数量。<BR>一个类用到的其他类的数目应当尽量少。 </P>
<P class=content>(23)尽量减少类和协作者之间传递的消息的数量。</P>
<P class=content>(24)尽量减少类和协作者之间的协作量，也即：减少类和协作者之间传递的不同消息的数量。</P>
<P class=content>(25)尽量减少类的扇出，也即：减少类定义的消息数和发送的消息数的乘积。</P>
<P class=content>(26)如果类包含另一个类的对象，那么包含类应当给被包含的对象发送消息。也即：包含关系总是意味着使用关系。</P>
<P class=content>(27)类中定义的大多数方法都应当在大多数时间里使用大多数数据成员。</P>
<P class=content>(28)类包含的对象数目不应当超过开发者短期记忆的容量。这个数目常常是6。<BR>当类包含多于6个数据成员时，可以把逻辑相关的数据成员划分为一组，然后用一个新的包含类去包含这一组成员。 </P>
<P class=content>(29)让系统功能在窄而深的继承体系中垂直分布。</P>
<P class=content>(30)在实现语义约束时，最好根据类定义来实现。这常常会导致类泛滥成灾，在这种情况下，约束应当在类的行为中实现，通常是在构造函数中实现，但不是必须如此。</P>
<P class=content>(31)在类的构造函数中实现语义约束时，把约束测试放在构造函数领域所允许的尽量深的包含层次中。</P>
<P class=content>(32)约束所依赖的语义信息如果经常改变，那么最好放在一个集中式的第3方对象中。</P>
<P class=content>(33)约束所依赖的语义信息如果很少改变，那么最好分布在约束所涉及的各个类中。</P>
<P class=content>(34)类必须知道它包含什么，但是不能知道谁包含它。</P>
<P class=content>(35)共享字面范围(也就是被同一个类所包含)的对象相互之间不应当有使用关系。</P>
<P class=content>(36)继承只应被用来为特化层次结构建模。</P>
<P class=content>(37)派生类必须知道基类，基类不应该知道关于它们的派生类的任何信息。</P>
<P class=content>(38)基类中的所有数据都应当是私有的，不要使用保护数据。<BR>类的设计者永远都不应该把类的使用者不需要的东西放在公有接口中。 </P>
<P class=content>(39)在理论上，继承层次体系应当深一点，越深越好。</P>
<P class=content>(40)在实践中，继承层次体系的深度不应当超出一个普通人的短期记忆能力。一个广为接受的深度值是6。</P>
<P class=content>(41)所有的抽象类都应当是基类。</P>
<P class=content>(42)所有的基类都应当是抽象类。</P>
<P class=content>(43)把数据、行为和/或接口的共性尽可能地放到继承层次体系的高端。</P>
<P class=content>(44)如果两个或更多个类共享公共数据(但没有公共行为)，那么应当把公共数据放在一个类中，每个共享这个数据的类都包含这个类。</P>
<P class=content>(45)如果两个或更多个类有共同的数据和行为(就是方法)，那么这些类的每一个都应当从一个表示了这些数据和方法的公共基类继承。</P>
<P class=content>(46)如果两个或更多个类共享公共接口(指的是消息，而不是方法)，那么只有他们需要被多态地使用时，他们才应当从一个公共基类继承。</P>
<P class=content>(47)对对象类型的显示的分情况分析一般是错误的。在大多数这样的情况下，设计者应当使用多态。</P>
<P class=content>(48)对属性值的显示的分情况分析常常是错误的。类应当解耦合成一个继承层次结构，每个属性值都被变换成一个派生类。</P>
<P class=content>(49)不要通过继承关系来为类的动态语义建模。试图用静态语义关系来为动态语义建模会导致在运行时切换类型。</P>
<P class=content>(50)不要把类的对象变成派生类。对任何只有一个实例的派生类都要多加小心。</P>
<P class=content>(51)如果你觉得需要在运行时刻创建新的类，那么退后一步以认清你要创建的是对象。现在，把这些对象概括成一个类。</P>
<P class=content>(52)在派生类中用空方法(也就是什么也不做的方法)来覆写基类中的方法应当是非法的。</P>
<P class=content>(53)不要把可选包含同对继承的需要相混淆。把可选包含建模成继承会带来泛滥成灾的类。</P>
<P class=content>(54)在创建继承层次时，试着创建可复用的框架，而不是可复用的组件。</P>
<P class=content>(55)如果你在设计中使用了多重继承，先假设你犯了错误。如果没犯错误，你需要设法证明。</P>
<P class=content>(56)只要在面向对象设计中用到了继承，问自己两个问题：(1)派生类是否是它继承的那个东西的一个特殊类型？(2)基类是不是派生类的一部分？ </P>
<P class=content>(57)如果你在一个面向对象设计中发现多重继承关系，确保没有哪个基类实际上是另一个基类的派生类。</P>
<P class=content>(58)在面向对象设计中如果你需要在包含关系和关联关系间作出选择，请选择包含关系。</P>
<P class=content>(59)不要把全局数据或全局函数用于类的对象的薄记工作。应当使用类变量或类方法。</P>
<P class=content>(60)面向对象设计者不应当让物理设计准则来破坏他们的逻辑设计。但是，在对逻辑设计作出决策的过程中我们经常用到物理设计准则。</P>
<P class=content>(61)不要绕开公共接口去修改对象的状态。</P><img src ="http://www.blogjava.net/nighthawk/aggbug/11261.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nighthawk/" target="_blank">nighthawk</a> 2005-08-26 22:36 <a href="http://www.blogjava.net/nighthawk/articles/11261.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>致面向对象技术初学者的一封公开信[Alistair Cockburn 著]</title><link>http://www.blogjava.net/nighthawk/articles/10685.html</link><dc:creator>nighthawk</dc:creator><author>nighthawk</author><pubDate>Mon, 22 Aug 2005 05:46:00 GMT</pubDate><guid>http://www.blogjava.net/nighthawk/articles/10685.html</guid><wfw:comment>http://www.blogjava.net/nighthawk/comments/10685.html</wfw:comment><comments>http://www.blogjava.net/nighthawk/articles/10685.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nighthawk/comments/commentRss/10685.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nighthawk/services/trackbacks/10685.html</trackback:ping><description><![CDATA[Alistair Cockburn 著（1996 年2 月），袁峰 译 <BR><BR>介绍 <BR>首先我要解释一下为什么会写这封公开信。这似乎已经成了一种习惯，但这个步骤还是需要的。过去6 年中， 我曾经无数次地在饭店、酒吧、旅店大厅等各种地方以同一种方式度过愉快而漫长的夜晚：和同样追求真理、光明和智慧的伙伴一起探讨面向对象的真谛。现在，我已经可以回答很多当年我遇到的问题。这些同样的问题也在困扰着我的一位新同事，在一家饭店里，我花了整整一个晚上和他讨论这些问题。结果第二天，他的同事又来问这些问题，并建议把我们的谈话内容记录下来，这样他可以拿去给他的同事看。考虑到还有很多和他的同事一样询问这些同样问题的人，我决定写下这篇文章。 <BR>主要的问题是： <BR>z 为什么只要稍有一点不是严格或纯面向对象的做法、说法，OO 专家就大惊小怪的？use case 并不是面向对象的，为什么还这么流行？而且，OO 建模似乎和数据建模非常相似？ <BR>z 数据建模（data model）得到的模型和对象模型的结构部分会不会很像？流程建模（process model）和对象模型的行为部分呢？ <BR>z 业务结构建模中为什么要用use case 和场景（scenario）? <BR>OO 的新手们反复问这些问题，但实际上，只有在日常工作中坚持应用面向对象的思维进行工作，积累一定的经验，才能得到满意的答案。为什么只要稍有一点不是严格或纯面向对象的做法、说法，OO 专家就大惊小怪的？use case 并不是面向对象的，为什么还这么流行？而且，OO 建模似乎和数据建模非常相似？ <BR>我想分三步来回答这个问题。 <BR><BR>首先，我举我和Bob（著名的OO 专家）一起工作的例子， 当我们讨论OO 的时候，彼此都有一个共识，知道对方拥有面向对象工作的丰富经验并且是这项技术的坚定支持者。而且，对诸如对象识别（object identity）、多态、数据和行为的封装、实例职责、继承等对象技术都是手到擒来。因此，当我说：“明天对程序表单进行数据建模吧”，Bob 不会产生我要会因为关系表而放弃对象这样的误解，他知道我指的是在对象模型中体现出来的结构化特性进行建模。他知道我会说些什么，因此我使用或误用这些术语不会造成什么误解。但作为一个对象技术的初学者，如果Bob 发现你把数据和行为完全分离开了， 并且没有使用（ 或者说忽视了）对象识别或者多态等技术， 这时候， 如果你说“ 数据建模”，Bob 会像一堵墙一样逼近你，直到你明白该怎样改变。这样工作几个月，你会发现，你的模型（以及建模）中渐渐有了对象识别、多态、数据和行为的绑定，这时候再用“ 数据建模”这个词就不是那么危险了， 但Bob 还可能会担心你走回到老路上。换句话说， 他对你还不够信任， 因此，你不得不很小心地使用这些术语。 <BR>就算一个对象模型可以分为“结构”和“行为”特性，我们也不会使用“对象建模”和“流程建模” 这种术语，以免引起混淆。事实上，为对象模型的“结构”特性建模可以看成是数据建模的特殊形式，只不过建模的对象不再是表，而是需要捕获的信息的结构。我们将它称为“ 概念数据模型”，而不是逻辑数据模型或物理数据模型。第二步，让我们考虑两个OO 使用者一起讨论的情况。如果其中一个家伙说到“流程建模”这样的词，肯定会让他的拍档琢磨半天：这家伙是说用标准数据流图作流程建模吗？如果这样的话，以后OO 实现的时候不是相当麻烦了吗？他是不是指模型的行为特性？是不是说在一个对象内部对流程进行建模？（如果这样的话，那会很有意思，因为很少有人这么做的。） 通过这个例子我们可以看到，这种谈话中使用“ 流程建模” 这种意图不明的词实在是太危险了，很容易就将交流变得非常困难。 <BR>最后来说use case 和场景的问题，它们都是获取需求的主要手段，和实现技术无关。其好处是可以为设计时的讨论提供内容和范围。它们不是“面向对象”的，这是事实，它们类似于功能分解，这也是事实，而且这一点吓坏了很多人，但这些都无所谓。重要的是它们为设计提供了内容，在用来描述内部设计时，它们表现了系统的行为。Flow chart 、交互图、Petri 网、数据流图、use case 都可以用来描述系统的行为特性， 但各自用途不同，各有优劣。关键是要知道：对象不仅有数据，也有行为， 认识到这一点， 就可以大胆地去考虑怎样可以更好地捕捉、描述对象内部和对象之间的行为。 <BR>数据建模（data model ）得到的模型和对象模型的结构部分会不会很像？流程建模（process model） 和对象模型的行为部分呢？根据我的经验，数据建模人员可以分为两种－一种是为存储的数据建模，而另一种是为系统或组织中的信息建模。这两者截然不同。前者讨论和思考所用的概念通常都很具体，比如说数据表。他们的模型和OO 建模者的模型大相径庭，而且他们并不愿意看到这些技术之间的相似性。在数据建模社区中，只有讨论逻辑数据模型或物理数据模型才不会受到攻击后者得到的是概念数据模型。根据我的经验，他们得到的模型和那些有经验的OO 建模者得到的模型非常相似。他们的工作更加类似于业务人员，而不是逻辑数据建模人员，这种说法可能会有助于理解概念数据模型和逻辑数据模型的区别。 <BR>似乎有一套学问可以帮助人们比OO 建模人员更快地得到结果。我多次发现这样的事实：OO 建模人员花了三四次迭代才得到的模型，实际上和（概念）数据建模人员一个循环得到的模型是一样的。这个发现使我对数据建模人员充满了敬佩。事实上，在进行对象设计的时候，我有时就直接去把数据建模人员的产品拷贝过来看看， 从中来看我最后得到的模型大概会是什么样的。 <BR>我曾经召开过数据建模人员和对象建模人员之间的会议。采取的方法是“ 一个听众的CRC 会议（CRC sessions for an audience）。四个经验丰富的OO 设计师坐在长桌一端，业务专家沿着长桌坐下，他们负责回答问题并纠正对业务的误解。接着是数据建模人员，长桌的另一头是其它有关人员。总的来说，屋里大概是十几个人，但谈话主要是在四个OO 设计师之间进行。 <BR>讨论大概一个小时之后，OO 设计师可以得到对象设计的一部分。这时候，咨询数据建模人员，这个模型和他们已经得到的模型本质上是不是一样的。他们说，“是的”，重复这个过程两次以上，每次都询问数据建模人员同样的问题，除了使用的符号技术是不同的，例如：他们没有用继承，但在同样的地方有同样的占位符，在本质上，这个模型和他们的模型没有什么不同的。接着，我们分成几个小组，每个小组包括一个业务专家、一个数据建模专家和一个OO 专家，很快就剩下的设计达成一致，找出技术上一些小的不同之处，并且进行排序。一般情况都是这样的：要么数据建模人员考虑得更加合理，要么OO 建模人员考虑得更加合理，小组要做的是在他们的设计之间进行协调。 <BR>从上面的这些经验可以看到，使用CRC 进行OO 建模得到的模型和概念数据建模得到的结果非常相似。另外，根据经验，基于逻辑（存储的信息）的关系建模和OO 建模是不同的。大多数情况下，区别是由于技术的不同导致的，例如，在OO 模型中可以自由地使用继承和多对多的关系。由于技术上的差异，两种建模人员之间不能很好地交流，这是最大的困难。 <BR>数据建模部分的问题就说这么多吧。 <BR>对流程建模而言， 情况却不一样了。90 年代初， 涌现出各种方法、计划、会议和项目，试图将数据流图的模型转变为对象模型。曾经有几个项目声称获得了成功，但都是后续无音，业界一致的结论是： 这个转变太困难了。大多数使用数据流图的建模人员最终都抛弃了这项技术， 投入了对象设计的怀抱（Martin-Odell 和Ptech 小组是著名的例外）。对于流程建模，现阶段我的回答是：其模型无法与OO 模型相比较。但这并不是最终的回答，OO 建模人员正在开始进行本质上的流程建模，下一步的发展将会怎样，我也并不清楚，流程将变成过程那样（过程编程复活？）， 或者变成数据流图那样，还是类似于封装的对象？ <BR>业务结构建模中为什么要用use case 和场景（scenario）? <BR>use case 和场景…… <BR>……为讨论提供范围和内容， <BR>……预示内容，包括什么，不包括什么，讨论多广，多深入，什么时候停止， <BR>……为设计的压力测试提供参数。 <BR>我见过一些不使用“场景”的小组，他们建模的时候实际上就是在问题域内作随机的探险。负责人根本不知道下一个该问什么问题？经常都是凭直觉。一般说来，他们也不知道现在捕获的信息最后是否真正需要，就算知道也是凭直觉或者瞎蒙。 <BR>在一个寂静的深夜，几个真正专家级的OO 设计师向我说了心里话：根本就没有一个有效的规则来指导漂亮的对象设计。其中一位说，“我们有时真的是在毫无目的地讨论”， 另一位也相当赞同，“有时候我们就象没头的苍蝇一样到处乱撞，直到突然把一些好的对象给撞出来。” <BR>使用场景也不能防止盲目的讨论和到处撞墙，只是可以为讨论提供内容和边界。我曾经见过有的小组不用场景，长时间在很大的建模范围内四处乱撞，失去控制。因此，使用场景和use case 的第一个理由就是为建模的努力提供一个范围。 <BR>使用场景的第二个理由是决定需求获取到什么程度算足够。 <BR>假设现在让你为一家货运公司建模。你建模的内容是什么？卡车的购买价值……实际价值……转售价值……车内颜色……快送单据的数目……旅途的数目和目的地？如果你想要把所有的内容都包括进来，那你将永远无法结束。除此之外，还有其它的问题：从何处开始，何时结束，包括什么，不包括什么，需要多少细节？ 场景可以回答关于内容的问题，答案是：你需要足以回答场景中所有问题的信息。在结构化模型或完全的对象模型中，如果用一个方框来对应一个场景。然后在浏览场景的过程中将涉及到的元素（译者注：这里的元素， 是比如在OO 的类或对象） 涂成红色， 会发现最后所有的元素都按某种顺序连接起来了（不会有遗漏的元素）。如果对所有的场景都执行这个操作，最后所有的元素都会被涂成红色。在建模过程中，讨论会经常离题，用这种方法可以保证针对当前的需要制定一个边界，这样不会跑题太远。 <BR>最后，场景还提供了压力测试的参数以保证质量。 <BR>怎样比较两个模型的优劣？ “和业务相符”，这是必要的，但肯定不够，可能有很多模型都可以“和业务相符”，怎样来度量这些模型的质量呢？ <BR>软件变更的成本很高，另外，变更越靠后，变更的成本也就越高。（变更成本曲线）。软件设计的一个目的就是将变更隔离开来，每次变更只需改变一个模块。这并不是什么时候都能做到的，正如Kent Beck 所说，“如果你可以只改变一个类， 那软件的质量将得到显著的提高”。和软件相比， 业务模型的成本函数并不是很清楚，但将变更影响的范围降低到最低肯定是应该的。 <BR>为了测试变更曲线，需要参数，而场景可以提供这些参数。如果用户想要“something-or-the-other”，怎么办？模型中到底需要多少元素？像CRC（class-responsibility-collaborator ）这样的技术鼓励用户在现场快速得到场景， 揭示可能的未来变更。最后，检查这些可能的变更，检查需要为之改动多少元素。对于两个都“和业务相符”的模型，哪个模型受场景影响的点少一些，哪个模型就要好一些。其它很多地方也可以找到压力测试的参数。例如相关产品的结构，变更时是不是可以只改一点就可以了？在评价模型时，这些参数都应该用上。 <BR>场景还可以用在很多地方，例如：同用户一起检查需求，为系统提供功能测试的用例。以上所说，就是在建模活动中采用场景的三个理由。<BR><BR>作者的网站：<A href="http://alistair.cockburn.us/">http://alistair.cockburn.us/</A><img src ="http://www.blogjava.net/nighthawk/aggbug/10685.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nighthawk/" target="_blank">nighthawk</a> 2005-08-22 13:46 <a href="http://www.blogjava.net/nighthawk/articles/10685.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Petstore中waf框架的源码研究笔记[转]</title><link>http://www.blogjava.net/nighthawk/articles/9785.html</link><dc:creator>nighthawk</dc:creator><author>nighthawk</author><pubDate>Thu, 11 Aug 2005 03:20:00 GMT</pubDate><guid>http://www.blogjava.net/nighthawk/articles/9785.html</guid><wfw:comment>http://www.blogjava.net/nighthawk/comments/9785.html</wfw:comment><comments>http://www.blogjava.net/nighthawk/articles/9785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nighthawk/comments/commentRss/9785.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nighthawk/services/trackbacks/9785.html</trackback:ping><description><![CDATA[waf是petstore中自带的web tier的MVC框架，虽然比起struts等框架，功能要略显简单，而且也显得过于冗余，但毕竟是一种很好的web层框架解决方案，还是值得我们研究一下的。<BR>我是从源码上入手的，可能会存在一些解释错误的地方，希望大家谅解！<BR><BR>waf包括在petstore（学习EJB的经典实例）中，我是从sun download的，最新版本是1.3.2，在其自带的doc里面有安装说明。在提供的源代码中包括了waf framework，我是把它放入jbuilder工程中进行研究。<BR><BR>Waf framework实际包括俩部分，web tier和EJB tier，WebController作为这俩层之间访问的proxy。Event(事件)作为这俩层交互时传递的对象，根据实际要求可以定义不同的事件对象，而作为EJB层也会提供对这些事件处理的业务方法。<BR>waf包括一个mappings.xml的文件用于定义事件映射和url映射。<BR><BR>web tier：<BR>在web tier包括一个Control(MainServlet)，用于接收客户端请求；一些继承自HtmlAction的action处理类(Model部分)，这个和struts里面是一样的，这些action处理类用于处理不同的客户端请求，用户请求的url和action之间的映射在mappings.xml中定义。<BR>action包括3个处理方法，doStart()、perform()、doEnd()，在perform()方法中，action除了进行一些web层的处理外还要决定触发哪个Event事件(即触发商业层的什么操作)，Control会根据action的返回事件通过proxy对象WebController对EJB tier进行调用。<BR><BR>EJB tier：<BR>和web tier一样EJB tier也是MVC结构的，包括Control(EJBControllerLocalEJB，一个local接口的会话bean)和Model(继承自EJBAction的action类)。每一个action类负责处理一个或多个事件Event，这个也是在mappings.xml中进行定义。在action当中会调用业务逻辑层的EJB(通常是一些facsade EJB)进行实际业务处理。<BR>waf为了保证一个client端所进行的所有业务处理可以是相关联的，即允许保存各业务处理状态，还提供了状态机StateMachine，用于保存业务操作时的处理状态。<BR><BR>mappings.xm：<BR>事件映射，用于EJB tier的处理：<BR>&lt;event-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;event-class&gt;com.sun.j2ee.blueprints.waf.event.events.ChangeLocaleEvent&lt;/event-class&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-action-class&gt;com.sun.j2ee.blueprints.waf.controller.ejb.action.actions.ChangeLocaleEJBAction&lt;/ejb-action-class&gt;<BR>&lt;/event-mapping&gt;<BR><BR>url映射，用于web tier的处理：<BR>&lt;url-mapping url="changelocale.do" screen="locale_change_success.screen" &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;web-action-class&gt;com.sun.j2ee.blueprints.waf.controller.web.action.actions.ChangeLocaleHTMLAction&lt;/web-action-class&gt;<BR>&lt;/url-mapping&gt;<BR><BR>waf的处理过程如下：<BR>1.客户端访问系统。<BR>2.在web.xml中定义的listener(servlet技术，默认为DefaultComponentManager)被激活，为当前客户端做初始化工作，包括创建EJB tier的代理对象WebController以及EJB tier的Control(EJBControllerLocalEJB，还包括当前记录当前客户端状态的StateMachine。<BR>3.客户端发出xxx.do的请求。<BR>4.web tier的Control(MainServlet)截获这个请求，这个在web.xml中进行定义。<BR>5.MainServlet调用request处理类RequestProcessor进行本次业务请求处理。<BR>6.RequestProcessor会到mappings.xml文件中读取这个请求对应的action，然后依次调用action的doStart()、perform()、doEnd()方法。<BR>7.action根据用户的request来决定产生什么处理事件Event。<BR>8.RequestProcessor将这个事件Event通过代理类WebController传递到EJB tier。<BR>9.EJB tier的控制器EJBControllerLocalEJB捕获到这个事件后首先到mappings.xml中检索哪个EJBAction负责处理这个事件。<BR>10.EJBControllerLocalEJB调用仅属于当前客户端的StateMachine负责处理本次操作。<BR>11.StateMachine依次调用EJBAction的doStart()、perform()、doEnd()方法。<BR>12.EJBAction的perform()除了调用业务逻辑层的EJB对象的业务方法，比如一些使用了facasde模式的会话bean，还可以将业务处理结果存放到和一些状态值存放到仅属于当前客户端的StateMachine当中。<BR>至此整个处理过程完成。<BR><BR>从waf的源码来看注释显得并不是很完善，因此对于理解带来了一些困难。虽然我们不一定是要使用它，但了解一下它的架构思想还是很有必要的。waf中采用的事件机制和struts显然有所不同。<BR><BR><BR><BR><BR>该帖由 sunyn 在 Jan 25, 2005 9:06 AM 编辑过<BR>
<P>&nbsp;</P><img src ="http://www.blogjava.net/nighthawk/aggbug/9785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nighthawk/" target="_blank">nighthawk</a> 2005-08-11 11:20 <a href="http://www.blogjava.net/nighthawk/articles/9785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE design patterns [转]</title><link>http://www.blogjava.net/nighthawk/articles/9380.html</link><dc:creator>nighthawk</dc:creator><author>nighthawk</author><pubDate>Fri, 05 Aug 2005 03:35:00 GMT</pubDate><guid>http://www.blogjava.net/nighthawk/articles/9380.html</guid><wfw:comment>http://www.blogjava.net/nighthawk/comments/9380.html</wfw:comment><comments>http://www.blogjava.net/nighthawk/articles/9380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nighthawk/comments/commentRss/9380.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nighthawk/services/trackbacks/9380.html</trackback:ping><description><![CDATA[<P>什么是Design Patten?</P>
<P>&nbsp;&nbsp;&nbsp; 简单来说，Design Patten 就是一个常用的方案。 在我们的开发过程中，经常会遇到一些相同或者相近的问题，每次我们都会去寻找一个新的解决方法，为了节省时间提高效率，我们提供一些能够解决这些常见问题的，被证实可行的方案，构成一个统一的资源库。<BR>&nbsp;&nbsp;&nbsp; 一个Design Patten描述了一个被证实可行的方案。这些方案非常普通，是有完整定义的最常用的模式。 这些模式可以被重用，有良好的伸缩性，而这些Design Patten的优势将在设计J2EE应用时得到体现。</P>
<P>1. Model-View-Controller</P>
<P>a. 问题<BR>&nbsp;&nbsp;&nbsp; 如果开发一个企业级应用，只需要一种客户端的话，那么一切都非常容易解决。但真实情况是，我们必须面对运行在各种设备上客户端，象PDA，WAP浏览器以及运行在桌面上的浏览器，我们不得不开发不同的应用程序来处理来自不同客户端的请求。数据访问与现实将混淆在一起，可能会出现重复的数据访问，导致整个开发周期没有必要的延长。</P>
<P>b. 建议的解决方法<BR>&nbsp;&nbsp;&nbsp; Model-View-Controller (MVC) 开发模式被证明是有效的处理方法之一。它可以分离数据访问和数据表现。你可以开发一个有伸缩性的，便于扩展的控制器，来维护整个流程。如图1所示为整个模式的结构。MVC模式可以被映射到多层企业级的J2EE应用上。<BR>§ 所有的企业数据以及商业逻辑可以作为模式。<BR>§ 视图可以通过模式访问数据，并根据客户端的要求来显示数据。视图必须保证当模式改变的时候，数据显示也必须同时改变。<BR>§ 控制器用来结合模式和视图，把客户端来的请求转换成模式能够理解并执行的请求，并且根据请求以及执行结果来决定下一次显示那一个视图。<BR>根据以上的逻辑，你可以象这样建立一个应用：<BR>§ 应用的商业逻辑由MVC中的模式也就是EJB来表现。模式必须处理由控制器传递过来的对数据的访问请求。<BR>§ 多个页面组成了MVC中的视图，这些视图必须随模式一起更新。<BR>§ 控制器是一系列接收用户动作的对象，他们把用户的请求转换成模式可理解的请求，并决定显示那一个页面当模式处理完请求后。</P>
<P>c. 要点<BR>§ MVC结构适用于那些多用户的，可扩展的，可维护的，具有很高交互性的系统。<BR>§ MVC可以很好的表达用户的交互和系统模式。<BR>§ 很方便的用多个视图来显示多套数据，是系统很方便的支持其他新的客户端类型。<BR>§ 代码重复达到最低。<BR>§ 由于分离了模式中的流控制和数据表现，可以分清开发者的责任，另外，也可以加快产品推向市场的时间。</P>
<P>2. Front Controller</P>
<P>a. 问题<BR>&nbsp;&nbsp;&nbsp; MVC给出了一个整个应用的松散的耦合架构。现在来看一下这样一个经常发生的情况。在某一个应用中，用户看到的视图和他所做的操作密切相关。这是一些具有高度交互性的页面，而这些页面之间含有高度的依赖性。在没有任何模式的时候，这个应用只是一个许多独立的页面的集合，维护和扩展变得异常困难。<BR>§ 当一个页面移动后，其他含有这个页面链接的文件，都必须修改。<BR>§ 当有一系列页面需要口令保护时，许多配置文件需要修改，或者页面需要包含新的标记。<BR>§ 当一个页面需要一个新的表示层时，页面中的标记要被重新安排。<BR>&nbsp;&nbsp;&nbsp; 当这个系统变得复杂时，这些问题将变得更糟。如果用MVC来解决的话，就变成一个如何管理控制器和视图之间交互的问题。</P>
<P>b. 建议的解决方法<BR>&nbsp;&nbsp;&nbsp; 前台控制模式可以解决这个问题。这个模式中，所有的请求都被传送到一个对象中。这个主要的对象将处理所有的请求，决定以后显示那一个视图，以及实现必要的安全需求。对于把视图显示以及其他功能实现集中到一个主要的对象中，将使修改变得很容易，对应用的修改，可以在所有视图中反映出来。</P>
<P>c. 要点<BR>§ 这个模式对于需要在多个含有动态数据的页面之间进行复杂导航的系统来说，是很有效的。<BR>§ 这个模式对于要在所有页面中都包含模板，转换等的应用来说，也是很有效的。<BR>§ 由于视图的选择集中在前端控制器上，因此，视图的导航变得更加容易理解和便于配置。<BR>§ 视图重用和变更会更加容易。<BR>§ 视图之间的复杂交互，使得控制器变得复杂。从而，当应用发展的时候，控制器将变得难以维护。不过，大部分情况下可以用XML映射来解决。<BR>§ 实现应用要求的安全性检验变得很简单。<BR>§ 这个模式不适合小型的，只显示静态内容的应用。</P>
<P>d. 样例<BR>§ RequestMappings.xml 文件映射了传入的请求，处理器以及下一个页面</P>
<P>useRequestHandler="true" <BR>requiresSecurityCheck="true" <BR>nextScreen="screen2.jsp"&gt;<BR>com.blah1.blah2.blah3.request1Handler</P>
<P>&nbsp;&nbsp;&nbsp; 以上这个文件是控制器的指定配置，控制器的代码如下：<BR>§ FrontControllerImpl.java 利用上面的XML实现了控制器<BR>// all required imports<BR>// exceptions to be caught appropriately wherever applicable</P>
<P>public class FrontControllerImpl extends HttpServlet {</P>
<P>// all required declarations, definitions<BR>private HashMap requestMappings;</P>
<P>public void init() {<BR>// load the mappings from XML file into the hashmap<BR>}</P>
<P>public void doPost(HttpServletRequest request, <BR>HttpServletResponse response)<BR>throws IOException, ServletException <BR>{<BR>doGet(request, response);<BR>}</P>
<P>public void doGet(HttpServletRequest request, HttpServletResponse response)<BR>throws IOException, ServletException {<BR>String currentPage= request.getPathInfo();<BR>// get all mapping info for "currentPage" from the hashmap<BR>// if "securityCheckRequired = true", do the security check<BR>// if "useRequestHandler = true", pass on the incoming request to the specified handler<BR>// forward the results to the given "nextScreen"<BR>}<BR>} <BR>&nbsp;&nbsp;&nbsp; 用这种方法实现的控制器将很容易维护，当应用有新的变动的时候，只要修改XML文件就能解决了。前台控制模式将使在视图和控制器之前有复杂交互的J2EE应用变得简单。</P>
<P><BR>3. Session Facade</P>
<P>a. 问题<BR>&nbsp;&nbsp;&nbsp; 前台控制给出了一个基于MVC的，能有效管理用户与J2EE应用之间进行的复杂交互。这个模式可以使处理页面的现实顺序和用户的并发请求变得简单。并且使增加和改变页面现实变得更加容易。<BR>另外一个常见的问题是，当EJB或者业务逻辑发生变化的时候，应用的客户端也必须随之改变。我们来看一下这个问题。<BR>&nbsp;&nbsp;&nbsp; 一般来说，为了表现一个账户中的用户，我们使用一个业务逻辑来表示账户中的信息，象用户名和口令，再用一个EJB来管理用户的个人信息，象爱好，语言等。当要创建一个新的账号或者修改一个已经存在的账号时，必须访问包含账号信息的EJB，读取个人信息，修改并且保存，这样的一个流程。<BR>&nbsp;&nbsp;&nbsp; 当然，这只是一个非常简单的例子，实际情况可能比这个复杂的多，象查看用户定制了哪些服务，检验客户信用卡的有效性，存放订单等。在这个案例中，为了实现一个完整的流程，客户端必须访问账户EJB来完成一系列适当的工作。下面的例子显示了一个Servlet客户端如何来控制一个用户订单。<BR>A servlet that does the workflow required for placing an order <BR>// all required imports;<BR>// exceptions to be caught appropriately wherever applicable;<BR>// This servlet assumes that for placing an order the account and<BR>// credit status of the customer has to be checked before getting the<BR>// approval and committing the order. For simplicity, the EJBs that<BR>// represent the business logic of account, credit status etc are<BR>// not listed</P>
<P>public class OrderHandlingServlet extends HttpServlet {</P>
<P>// all required declarations, definitions</P>
<P>public void init() {<BR>// all inits required done here<BR>}</P>
<P>public void doPost(HttpServletRequest request, HttpServletResponse response)<BR>throws IOException, ServletException {<BR>// other logic as required<BR>// Get reference to the required EJBs<BR>InitialContext ctxt = new InitialContext();<BR>Object obj = ctxt.lookup("java:comp/env/ejb/UserAccount");<BR>UserAccountHome acctHome = (UserAccountHome)<BR>PortableRemoteObject.narrow(obj, UserAccountHome.class);<BR>UserAccount acct = acctHome.create();<BR>obj = ctxt.lookup("java:comp/env/ejb/CreditCheck");<BR>CreditCheckHome creditCheckHome = (CreditCheckHome)<BR>PortableRemoteObject.narrow(obj, CreditCheckHome.class);<BR>CreditCheck credit = creditCheckHome.create();<BR>obj = ctxt.lookup("java:comp/env/ejb/Approvals");<BR>ApprovalsHome apprHome = (ApprovalsHome)<BR>PortableRemoteObject.narrow(obj, ApprovalsHome.class);<BR>Approvals appr = apprHome.create();<BR>obj = ctxt.lookup("java:comp/env/ejb/CommitOrder");<BR>CommitOrderHome orderHome = (CommitOrderHome)<BR>PortableRemoteObject.narrow(obj, CommitOrderHome.class);<BR>CommitOrder order = orderHome.create();</P>
<P>// Acquire the customer ID and order details;<BR>// Now do the required workflow to place the order<BR>int result = acct.checkStatus(customerId);<BR>if(result != OK) {<BR>// stop further steps<BR>}<BR>result = credit.checkCreditWorth(customerId, currentOrder);<BR>if(result != OK) {<BR>// stop further steps<BR>}<BR>result = appr.getApprovals(customerId, currentOrder);<BR>if(result != OK) {<BR>// stop further steps<BR>}</P>
<P>// Everything OK; place the order<BR>result = order.placeOrder(customerId, currentOrder);</P>
<P>// do further processing as required<BR>}<BR>} <BR>&nbsp;&nbsp;&nbsp; 以上的代码显示了一个单个的客户端。如果这个应用支持多种客户端的话，必须为每一个客户端制定一种处理方法来完成工作流程。如果有一个EJB的实现流程需要改变的话，那么所有的参与这个流程的客户端都需要改变。如果不同的EJB之间的交互需要改变的话，所有的客户端都必须知道这一点，如果流程中需要增加一个新的步骤的话，所有的客户端也必须随之修改。 <BR>&nbsp;&nbsp;&nbsp; 这样一来，EJB和客户端之间的改变变得非常困难。客户端必须对每个EJB分开进行访问，致使网络速度变慢。同样，应用越复杂，麻烦越大。</P>
<P>b. 建议的解决方法<BR>&nbsp;&nbsp;&nbsp; 解决这个问题的方法是，把客户端和他们使用的EJB分割开。建议适用Session Fa?ade模式。这个模式通过一个Session Bean，为一系列的EJB提供统一的接口来实现流程。事实上，当客户端只是使用这个接口来触发流程。这样，所有关于EJB实现流程所需要的改变，都和客户端无关。<BR>&nbsp;&nbsp;&nbsp; 看下面这个例子。这段代码用来控制与客户相关的订单的处理方法。<BR>// All imports required<BR>// Exception handling not shown in the sample code</P>
<P>public class OrderSessionFacade implements SessionBean {</P>
<P>// all EJB specific methods like ejbCreate defined here<BR>// Here is the business method that does the workflow <BR>// required when a customer places a new order</P>
<P>public int placeOrder(String customerId, Details orderDetails) <BR>throws RemoteException {<BR>// Get reference to the required EJBs<BR>InitialContext ctxt = new InitialContext();<BR>Object obj = ctxt.lookup("java:comp/env/ejb/UserAccount");<BR>UserAccountHome acctHome = (UserAccountHome)<BR>PortableRemoteObject.narrow(obj, UserAccountHome.class);<BR>UserAccount acct = acctHome.create();<BR>obj = ctxt.lookup("java:comp/env/ejb/CreditCheck");<BR>CreditCheckHome creditCheckHome = (CreditCheckHome)<BR>PortableRemoteObject.narrow(obj, CreditCheckHome.class);<BR>CreditCheck credit = creditCheckHome.create();<BR>obj = ctxt.lookup("java:comp/env/ejb/Approvals");<BR>ApprovalsHome apprHome = (ApprovalsHome)<BR>PortableRemoteObject.narrow(obj, ApprovalsHome.class);<BR>Approvals appr = apprHome.create();<BR>obj = ctxt.lookup("java:comp/env/ejb/CommitOrder");<BR>CommitOrderHome orderHome = (CommitOrderHome)<BR>PortableRemoteObject.narrow(obj, CommitOrderHome.class);<BR>CommitOrder order = orderHome.create();</P>
<P>// Now do the required workflow to place the order<BR>int result = acct.checkStatus(customerId);<BR>if(result != OK) {<BR>// stop further steps<BR>}<BR>result = credit.checkCreditWorth(customerId, currentOrder);<BR>if(result != OK) {<BR>// stop further steps<BR>}<BR>result = appr.getApprovals(customerId, currentOrder);<BR>if(result != OK) {<BR>// stop further steps<BR>}</P>
<P>// Everything OK; place the order<BR>int orderId = order.placeOrder(customerId, currentOrder);</P>
<P>// Do other processing required</P>
<P>return(orderId);<BR>}</P>
<P>// Implement other workflows for other order related functionalities (like <BR>// updating an existing order, canceling an existing order etc.) in a <BR>// similar way<BR>} <BR>&nbsp;&nbsp;&nbsp; 在模式允许的情况下，Servlet代码将很容易实现。<BR>// all required imports<BR>// exceptions to be caught appropriately wherever applicable</P>
<P>public class OrderHandlingServlet extends HttpServlet {</P>
<P>// all required declarations, definitions</P>
<P>public void init() {<BR>// all inits required done here<BR>}</P>
<P>public void doPost(HttpServletRequest request, HttpServletResponse response)<BR>throws IOException, ServletException {<BR>// other logic as required<BR>// Get reference to the session facade<BR>InitialContext ctxt = new InitialContext();<BR>Object obj = ctxt.lookup("java:comp/env/ejb/OrderSessionFacade");<BR>OrderSessionFacadeHome facadeHome = (OrderSessionFacadeHome)<BR>PortableRemoteObject.narrow(obj, OrderSessionFacadeHome.class);<BR>OrderSessionFacade facade = facadeHome.create();</P>
<P>// trigger the order workflow<BR>int orderId = facade.placeOrder(customerId, currentOrder);</P>
<P>// do further processing as required<BR>}<BR>} <BR>&nbsp;&nbsp;&nbsp; 就象上面显示的，客户端的逻辑变得非常简单。流程中的任何改变只要修改模式中的一处地方就可以了。客户端可以仍旧使用原来的接口，而不必做任何修改。同样，这个模式可以用来响应其他处理器的流程处理。这让你能用同样的模式来处理不同客户端的不同流程。在这个例子中，模式提供了很好的伸缩性和可维护性。</P>
<P>c. 要点<BR>§ 既然这种模式不涉及到数据访问，就应该用Session Bean来实现。<BR>§ 对于用简单接口来实现复杂EJB的子系统来说，是一个理想的选择。<BR>§ 这个模式不适用于无流程处理的应用。<BR>§ 这个模式可以减少客户端于EJB之间的通信和依赖。<BR>§ 所有和EJB有关的交互，都有同一个Session Bean来控制，可以减少客户端对EJB的误用。<BR>§ 这个模式可以使支持多类型客户端变得更容易。<BR>§ 可以减少网络数据传递。<BR>§ 所有的服务器端的实现细节都对客户端隐藏，在改变发生后，客户端不用重新发布。<BR>§ 这个模式可以同样看成一个集中处理器来处理所有的安全或日志纪录。</P>
<P>4. Data Access Object</P>
<P>a. 问题<BR>&nbsp;&nbsp;&nbsp; 目前为止，你看到的模型都是用来构建可伸缩的，易于维护的J2EE应用。这些模式尽可能的把应用在多个层上来实现。但是，还有一点必须强调：EJB的数据表现。它们包括象EJB这样的数据库语言。如果数据库有改变的话，相应的SQL也必须改变，而EJB也必须随之更新。<BR>&nbsp;&nbsp;&nbsp; 这些常见问题就是：访问数据源的代码与EJB结合在一起，这样致使代码很难维护。看以下的代码。<BR>An EJB that has SQL code embedded in it <BR>// all imports required<BR>// exceptions not handled in the sample code</P>
<P>public class UserAccountEJB implements EntityBean {</P>
<P>// All EJB methods like ejbCreate, ejbRemove go here<BR>// Business methods start here</P>
<P>public UserDetails getUserDetails(String userId) {</P>
<P>// A simple query for this example<BR>String query = "SELECT id, name, phone FROM userdetails WHERE name = " + userId;</P>
<P>InitialContext ic = new InitialContext();<BR>datasource = (DataSource)ic.lookup("java:comp/env/jdbc/DataSource");<BR>Connection dbConnection = datasource.getConnection();<BR>Statement stmt = dbConnection.createStatement();<BR>ResultSet result = stmt.executeQuery(queryStr);</P>
<P>// other processing like creation of UserDetails object</P>
<P>result.close();<BR>stmt.close();<BR>dbConnection.close();<BR>return(details);<BR>}<BR>} <BR>b. 建议的解决方法<BR>&nbsp;&nbsp;&nbsp; 为了解决这个问题，从而让你能很方便的修改你的数据访问。建议使用DAO模式。这个模式把数据访问逻辑从EJB中拿出来放入独立的接口中。结果是EJB保留自己的业务逻辑方法，在需要数据的时候，通过DAO来访问数据库。这样的模式，在要求修改数据访问的时候，只要更新DAO的对象就可以了。看以下的代码。<BR>A Data Access Object that encapsulates all data resource access code <BR>// All required imports<BR>// Exception handling code not listed below for simplicity </P>
<P>public class UserAccountDAO {</P>
<P>private transient Connection dbConnection = null;</P>
<P>public UserAccountDAO() {}</P>
<P>public UserDetails getUserDetails(String userId) {</P>
<P>// A simple query for this example<BR>String query = "SELECT id, name, phone FROM userdetails WHERE name = " + userId;</P>
<P>InitialContext ic = new InitialContext();<BR>datasource = (DataSource)ic.lookup("java:comp/env/jdbc/DataSource");<BR>Connection dbConnection = datasource.getConnection();<BR>Statement stmt = dbConnection.createStatement();<BR>ResultSet result = stmt.executeQuery(queryStr);</P>
<P>// other processing like creation of UserDetails object</P>
<P>result.close();<BR>stmt.close();<BR>dbConnection.close();<BR>return(details);<BR>}</P>
<P>// Other data access / modification methods pertaining to the UserAccountEJB<BR>} <BR>&nbsp;&nbsp;&nbsp; 现在你有了一个DAO对象，利用这个对象你可以访问数据。再看以下的代码。<BR>An EJB that uses a DAO <BR>// all imports required<BR>// exceptions not handled in the sample code</P>
<P>public class UserAccountEJB implements EntityBean {</P>
<P>// All EJB methods like ejbCreate, ejbRemove go here</P>
<P>// Business methods start here</P>
<P>public UserDetails getUserDetails(String userId) {</P>
<P>// other processing as required<BR>UserAccountDAO dao = new UserAccountDAO();<BR>UserDetails details = dao.getUserDetails(userId);<BR>// other processing as required<BR>return(details);<BR>}<BR>} <BR>&nbsp;&nbsp;&nbsp; 任何数据源的修改只要更新DAO就可以解决了。另外，为了支持应用能够支持多个不同的数据源类型，你可以开发多个DAO来实现，并在EJB的发布环境中指定这些数据源类型。在一般情况下，EJB可以通过一个Factory对象来得到DAO。用这种方法实现的应用，可以很容易的改变它的数据源类型。</P>
<P><BR>c. 要点<BR>§ 这个模式分离了业务逻辑和数据访问逻辑。<BR>§ 这种模式特别适用于BMP。过一段时间，这种方式同样可以移植到CMP中。<BR>§ DAOs可以在发布的时候选择数据源类型。<BR>§ DAOs增强了应用的可伸缩性，因为数据源改变变得很容易。<BR>§ DAOs对数据访问没有任何限制，甚至可以访问XML数据。<BR>§ 使用这个模式将导致增加一些额外的对象，并在一定程度上增加应用的复杂性。</P><img src ="http://www.blogjava.net/nighthawk/aggbug/9380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nighthawk/" target="_blank">nighthawk</a> 2005-08-05 11:35 <a href="http://www.blogjava.net/nighthawk/articles/9380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>What is Pattern ?Here is Definition</title><link>http://www.blogjava.net/nighthawk/articles/9249.html</link><dc:creator>nighthawk</dc:creator><author>nighthawk</author><pubDate>Thu, 04 Aug 2005 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/nighthawk/articles/9249.html</guid><wfw:comment>http://www.blogjava.net/nighthawk/comments/9249.html</wfw:comment><comments>http://www.blogjava.net/nighthawk/articles/9249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nighthawk/comments/commentRss/9249.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nighthawk/services/trackbacks/9249.html</trackback:ping><description><![CDATA[<P class=docText>Patterns are about communicating problems and solutions. Simply put, patterns enable us to document a known recurring problem and its solution in a particular context, and to communicate this knowledge to others. One of the key elements in the previous statement is the word <SPAN class=docEmphasis>recurring,</SPAN> since the goal of the pattern is to foster conceptual reuse over time.</P>
<P class=docText>We explore this in more detail in <A class=docLink href="mk:@MSITStore:E:\Downloads\Core%20J2EE%20Patterns%202nd%20Editioin.chm::/0131422464/ch05.html#ch05">Chapter 5</A>, in the section "<A class=docLink href="mk:@MSITStore:E:\Downloads\Core%20J2EE%20Patterns%202nd%20Editioin.chm::/0131422464/ch05lev1sec1.html#ch05lev1sec1">What Is a Pattern?</A>" on page 118.</P>
<P class=docText>This well-known pattern definition comes from Christopher Alexander in <SPAN class=docEmphasis>A Pattern Language</SPAN> [<A class=docLink href="mk:@MSITStore:E:\Downloads\Core%20J2EE%20Patterns%202nd%20Editioin.chm::/0131422464/biblio01div01.html#biblio01div01entry02">Alex2</A>]:<A name=idd1e2194></A><A name=idd1e2199></A></P>
<BLOCKQUOTE>
<P class=docText>Each pattern is a three-part rule, which expresses a relation between a certain context, a problem, and a solution.</P>
<P class=docText>—<SPAN class=docEmphasis>Christopher Alexander</SPAN></P></BLOCKQUOTE>
<P class=docText>Alexander expands his definition further, and noted patterns figure Richard Gabriel [<A class=docLink href="mk:@MSITStore:E:\Downloads\Core%20J2EE%20Patterns%202nd%20Editioin.chm::/0131422464/biblio01div01.html#biblio01div01entry13">Gabriel</A>] discusses this definition in more detail [<A class=docLink href="mk:@MSITStore:E:\Downloads\Core%20J2EE%20Patterns%202nd%20Editioin.chm::/0131422464/biblio01div02.html#biblio01div02entry02">Hillside</A>]. Gabriel offers his own version of Alexander's definition as applied to software:</P>
<BLOCKQUOTE>
<P class=docText>Each pattern is a three-part rule, which expresses a relation between a certain context, a certain system of forces which occurs repeatedly in that context, and a certain software configuration which allows these forces to resolve themselves. [See A Timeless Way of Hacking.]</P>
<P class=docText>—<SPAN class=docEmphasis>Richard Gabriel</SPAN></P></BLOCKQUOTE>
<P class=docText>This is a fairly rigorous definition, but there are also much looser ones. For example, Martin Fowler offers the following definition in <SPAN class=docEmphasis>Analysis Patterns</SPAN> [<A class=docLink href="mk:@MSITStore:E:\Downloads\Core%20J2EE%20Patterns%202nd%20Editioin.chm::/0131422464/biblio01div01.html#biblio01div01entry11">Fowler2</A>]:</P>
<BLOCKQUOTE>
<P class=docText>A pattern is an idea that has been useful in one practical context and will probably be useful in others.</P>
<P class=docText>—<SPAN class=docEmphasis>Martin Fowler</SPAN></P></BLOCKQUOTE>
<P class=docText>As you can see, there are many definitions for a pattern, but all these definitions have a common theme relating to the recurrence of a problem/solution pair in a particular context.</P>
<P class=docText>Some of the common characteristics of patterns are as follows:<A name=idd1e2252></A><A name=idd1e2255></A></P>
<UL>
<LI>
<P class=docList>Patterns are observed through experience.</P>
<LI>
<P class=docList>Patterns are typically written in a structured format (see "<A class=docLink href="mk:@MSITStore:E:\Downloads\Core%20J2EE%20Patterns%202nd%20Editioin.chm::/0131422464/ch05lev1sec4.html#ch05lev2sec8">Pattern Template</A>" on page 129).</P>
<LI>
<P class=docList>Patterns prevent reinventing the wheel.</P>
<LI>
<P class=docList>Patterns exist at different levels of abstraction.</P>
<LI>
<P class=docList>Patterns undergo continuous improvement.</P>
<LI>
<P class=docList>Patterns are reusable artifacts.</P>
<LI>
<P class=docList>Patterns communicate designs and best practices.</P>
<LI>
<P class=docList>Patterns can be used together to solve a larger problem.</P></LI></UL>
<P class=docText>Many great minds have spent a significant amount of time attempting to define and refine the notion of a software pattern. Suffice it to say, we do not presume to be great minds, nor do we wish to spend time expanding these discussions. Instead, we attempt to be true to aspects of these various definitions, focusing on the most simple and recurring theme in each.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---------------from Core J2ee Patterns</P><img src ="http://www.blogjava.net/nighthawk/aggbug/9249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nighthawk/" target="_blank">nighthawk</a> 2005-08-04 16:11 <a href="http://www.blogjava.net/nighthawk/articles/9249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>