??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品tv久久久久久久久久,亚洲AV无码专区亚洲AV伊甸园,亚洲情A成黄在线观看动漫软件http://m.tkk7.com/zhanglijun33/category/17948.htmlhQ彷徨,立志Q蓄?..zh-cnFri, 10 Jul 2015 03:46:47 GMTFri, 10 Jul 2015 03:46:47 GMT60apache+jk+tomcat集群+session同步 http://m.tkk7.com/zhanglijun33/archive/2015/07/08/426099.html无?/dc:creator>无?/author>Wed, 08 Jul 2015 10:26:00 GMThttp://m.tkk7.com/zhanglijun33/archive/2015/07/08/426099.htmlhttp://m.tkk7.com/zhanglijun33/comments/426099.htmlhttp://m.tkk7.com/zhanglijun33/archive/2015/07/08/426099.html#Feedback0http://m.tkk7.com/zhanglijun33/comments/commentRss/426099.htmlhttp://m.tkk7.com/zhanglijun33/services/trackbacks/426099.html阅读全文

]]>
关于Java23U设计模式的有趣见解http://m.tkk7.com/zhanglijun33/archive/2008/01/29/modes.html无?/dc:creator>无?/author>Tue, 29 Jan 2008 06:35:00 GMThttp://m.tkk7.com/zhanglijun33/archive/2008/01/29/modes.htmlhttp://m.tkk7.com/zhanglijun33/comments/178360.htmlhttp://m.tkk7.com/zhanglijun33/archive/2008/01/29/modes.html#Feedback2http://m.tkk7.com/zhanglijun33/comments/commentRss/178360.htmlhttp://m.tkk7.com/zhanglijun33/services/trackbacks/178360.html阅读全文

]]>
软g产品开发,Z么失?/title><link>http://m.tkk7.com/zhanglijun33/archive/2006/09/03/acticle.html</link><dc:creator>无?/dc:creator><author>无?/author><pubDate>Sun, 03 Sep 2006 09:38:00 GMT</pubDate><guid>http://m.tkk7.com/zhanglijun33/archive/2006/09/03/acticle.html</guid><wfw:comment>http://m.tkk7.com/zhanglijun33/comments/67429.html</wfw:comment><comments>http://m.tkk7.com/zhanglijun33/archive/2006/09/03/acticle.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://m.tkk7.com/zhanglijun33/comments/commentRss/67429.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/zhanglijun33/services/trackbacks/67429.html</trackback:ping><description><![CDATA[ <p>软g产品开发,Z么失?/p> <p>转自Liu Hang</p> <p>软g产品开发,Z么失败?在做了四q的软g开发,亲nl历了几个失败案例之后,我不得不对这个问题进行反思。我所接触到的朋友多半是做软g开发的Q他们和我一Pl历p|的例子比成功的要多得多。从|上的各U文章、论坛得来的信息也一样充满着悲观。ؓ什么这么多的失败?对于q个问题Q有着各种各样的答案。诸如需求不明,不断改变Q项目管理؜乱,旉一拖再拖;技术方案出错,技术难题解决不了;人员动频繁Q品出来后没有市场、没有竞争力{等问题Q不一而。正是失败的原因各种各样Q在产品开发的q程中要面一个又一个的险W与暗C,而每一个都有可能是致命的威胁。如何面对这些危险,l过q些险WQ以下一些是我个人的思考。把软g开发看作一个整体的程Q本文试图从产品开发的整个程来阐q我们会遇到的种U问题已及提Z些自q见解?/p> <p> </p> <p>一、Y件品的立项</p> <p>一个Y件品的开发和目有着许多不同Q一般来_软g目(project)都是因ؓ有了明确的客P或者已l有了合同或意向而开始启动的。Y件?product)则完全不一样了。在一个品没有开发出来之前,基本上没有客戗当然也有h仅仅凭着一套大脑中的想法或概念p扑ֈ客户Q对q些人我只有佩服。当然大多数公司只能先拿Z套自q产品L销Q才有可能找到定单。所以就有了做品的x?/p> <p>在这些Y件公怸又可以分两种情况。一U是在某个行业做了多个项目,也积累了一些行业、技术等l验。每一个新的项目都要重复很多同L工作Q效率自然不高了。这时公司很自然的想到要有自q产品。于是开始品的立项了?/p> <p>另外一U公司则完全不是q样。他们不是在某个行业做过多少目Q甚x本没有做q一个项目,p雄心勃勃的去做品。这U情冉|天都在发生。他们以前可能做pȝ集成的,可能卖硬件的Q或许根本就不是IT行业的,或者恰好做了一个项目,现在他们要进军Y件行业了Q所以急切的要做出自己的品去打市场。于是他们在一番调查论证后Q开始了产品的立V?/p> <p>在这两种情况下,可以明显的看得出前一U公司的基础要好得多Q成功的几率也要大多多。但qƈ不表明后一U就会失败。在目前阶段关键是看他有没有全面的调查论证,q入q个软g行业Q做q个产品是否可行。很多品的p|Q从一开始就注定的了。公司没做过多少认真的论证就匆匆开始了。Y件行业,产品开发都有着自n的很多规律,如果公司的决{层、领导层没有l验Q也没有d习,拿着别的行业的经验去套用它,那失败也׃q了。D个简单的例子QY件开发中人力资源是最重要的。Y件开发h员的薪水在各个行业中是算非常高的了,特别对于有丰富经验的人才更是与此。从传统行业q来的领导层如果不明白这点,也就找不CU的h才了?/p> <p>无论哪种公司Q他们在做品立Ҏ都要做好以下的心里准备:</p> <p>?       软g产品开发投资是很大的,特别是对哪些惛_大型的、优U产品的公司?/p> <p>?       软g产品开发周期也是比较长的。两、三q做一个品是很常见的。不要认为半q就可以做一个很好的产品</p> <p>?       软g产品是很Ҏp|的。既有可能品开发不出来Q也有可能没有市场?/p> <p> </p> <p>如果一个公司没有这些心里准备,那结果就很可能失败。ؓ什么这么说Q以我的亲nl历来说吧。我曄做过的一家公司,主要业务是做pȝ集成的。后来开始了一个物Y件的产品开发。在2000q左叻I物流行业软g刚刚兴vQ也是一个比较好的方向。公司组Z一个开发团队,开始了长达两年的曲折的研发q程。由于在研发q程中遇到的U种问题Q无法给公司领导层一个明的l果Q在研发开始初见曙光的时候,公司高层l止了这个品。公司的高层忍受不了大量的投资和q长的时间。Q何想做品的公司都一定要有这些心里准备,要充分估计投资额和研发周期?/p> <p>假设公司l过了充分的Q也有了一定的投资和时间预,产品立项了。但q只是一个良好的开端,因ؓ下面的Q何一个过E的p|Q都有可能导致全盘皆输?/p> <p> </p> <p>二、团队构?/p> <p>产品立项后,p开始组建研发团队了。Y件开发是一个既要高度协作、又有独立创造的智力zd。所以h的因素是关系C品开发能否成功的一个重要方面。应该说产品能否研发成功Q研发团队的合理构徏是关键性的。一个公司的领导层或许没有多Y件研发的l验Q但必须要保证能构徏一个合理的研发团队。就点很Ҏ理解Q就是让合适的人去做合适的事。不q反q来_如果领导层没有Y件研发的l验Q那也很难构Z个合理的团队。那怎样构徏一个好的团队呢Q这个问题没有一个非常普遍的{案。各个品的规模、技术难度都不相同,{案也不一栗?/p> <p>我们时常看到的情冉|Q公怼d一个研发经理或叫PM,负责整个研发q程。于是问题就出来了。这个PM是负责管理工作还是技术工作,或者两个都一赯责?怎样规定PM的职责权限?如果没有对这个问题的明确{案Q那危险随之而来的。就来我的经历过的来说吧?/p> <p>在离开上一家公司后Q我来到另一家Y件公司做|上教育q_的品研发。前期阶D可以说没有一个专职的目l理Q管理工作基本上׃个做技术的Team LeaderQ架构师Q负责,虽说也有不少问题Q但大家基本上还是团l在一起安步就班的工作。后来公ؓ我们团队招来一个PMQ此君是龟z,在国外、学习工作好几年Q也有技术背景。我们对他也充满期待。没惛_q了不久Q他居然把我们的Team Leaderl开了,找了一些大安不认可的理由。ƈ自Q技术负责hQ对我们的大部分的技术方案都持否定态度Qƈ严厉要求我们服从他的技术领对{如果他_N技术也qŞ了,关键是他的技术一点也不怎样Q还自我感觉良好。那最l的l果可想而知了。品基本上p|Q技术h员纷U槽,最后,q个 PM也只得走Z?/p> <p>q样的故事每天都在发生,大量的技术h员在抱怨领g懂技术,瞎指挥。在我的案例中,可以明显的感觉到Q公司对q个PM没有明确的职责划分,或者这个PM没有摆正自己的位|。这个PM应该做做理工作Q而不是负责技术?/p> <p>做Y件开发的都知道,一个团队中一般都有一个技术领|或者叫架构师(ArchitectQ?那他和PM怎样划分职责Q?</p> <p>如果要开发的产品规模比较大,比如人员数达?0Z上。这旉临的理、组l工作比较多Q公司应该考虑L一位专职的PM来负责这斚w的工作。他的主要工作包括h员招聘,提供开发团队所需资源Q制定计划,监督实施{,同时Q他应该是一个能够鼓动士气,懂得调动员工U极性的亲善的领ghQ对作ؓ一个PM的职位来_个h的素质和性格应该h更决定性的意义Q他主要工作是ؓ研发团队提供一切必要的服务Q监督的作用应该包含其中。在q样的团队里Q必d在一位架构师来全面负责技术工作,他有权独立决定技术方案,他与PM的关pL团结与合作,而不是领导和被领|架构师应该得到PM应有的尊重,而这点在中国很难做到。很多PMq涉架构师的技术工作,甚至赯代之,造成团队之间的؜乱。上面的案例正是说明了这一炏V架构师一般都是有一点完主义,他L希望看到产品做得更加Q但q是否让产品开发走向不可控制的地步Q事实上Q架构师要对现实情况作出妥协Q如旉、资金的限制Q,也就是对PM作出妥协。如果说PM代表旉、资源的现实MQ那么架构师׃表着完美的理想主义,他们是在不断的合作、妥协中共同推动产品的发展?/p> <p>对于开发的产品规模较小Q也可以完全不设|专职的PM。设|一位Team LeaderQ他既负责整个技术、也同时负责团队的管理工作。如果认担较重的话,可以为Team Leader配置一位秘书(目理人员Q,他的主要功能是辅助Team Leader做一些管理方便的工作。如人员招聘的准备工作、开发计划的监督{等?/p> <p>当团队合理的构徏之后Q下面的p入了产品研发的核心流E了?/p> <p> </p> <p>三、业务徏?amp;需求分?</p> <p>前面的过E更多的是由企业领导层决定的Q当我们技术h员进入这个团队时Q只能祈讨已l有了一个好的开始:公司下定军_要研发这个品,有一个优U的、明白自p责的PM。现在已及下面的所有流E都和技术h员(包括需求h员)密切相关Q是技术h员决定着产品成|与否的时候了?/p> <p>无论做品还是项目,W一步做需求分析,q一Ҏȝ疑。几乎每一个做软g的都知道Q需求的重要性。可是ؓ什么那么多的品或目最后失败的主要原因是需求问题呢Q?/p> <p>在Y件研发中Q品的业务需求比目的业务需求更难以定。品一般面对的是某个行业的通用需求,涉及的客户面更广Q合理的提取q些需求以形成更通用的品本w就是一件很困难的工作。对于一些以前没有这些行业经验的软g公司来说Q这更困难了。很多公司真因ؓ没有很好d需求分析的工作而导致品的p|。在我以前做物流的那家公叔RQ也是犯了这样严重的错误。我们当时对物流行业q不熟悉Q也不能很好的把握业务需求,产品研发在来回反复的q程中消耗了大量的时间与_֊?/p> <p>对于q个问题的解冻I几乎所有的软g工程Ҏ都提Z好的ҎQ引入领域业务专ӞDomain ExpertQ。我们的研发团队中,一定要有这L角色Q即使我们没有这样一个专职h员,但一定要有h扮演cM的角Ԍ例如架构师)。业务专家可以和架构师一赯行业务徏模的工作Q而架构师则偏重于技术方面,把业务模型{化成pȝ需求,按照RUP的流E来_是最l变成一个个Use Case。而一个好的业务专家是非常隑־的,q就是ؓ什么很多公司有q个意识而没有做好需求工作的重要原因Q由于资金、时间等各方面的限制Q他们最l放弃了q一步,而把希望寄托在架构师或其他开发h员n上,而这其中的风险就可想而知了?/p> <p>也有很多公司没有业务专家Q而把q个角色附加l架构师了。他们要求架构师既要_N业务,也要_N技术。而现实中Q这L人凤毛麟角,属于可遇而不可求的那一cR所以在q类角色没有很明分开的品研发中Q得到的东西要么是需求方面做得不够好Q要么在软g架构斚w不o人满意?/p> <p>怎样最大程度保证需求的合理Q我个h认ؓ做一个品的界面原型是一个好的方法。这一点在做一个基于browser的应用系l时更可行:Ҏ业务需求做出整个的面原型Q这L面也许很粗p,后台也不需要Q何的E序q行Q但可以Ҏq些面元素及之间的程来验证业务需求是否合理、正。这U方法应用到目开发(相对于品)中,可以和客户一起验证需求,l过几次反复Q可以比较准的理解、把握客L真实需求。这L工作耗费旉不多Q但却能起到很大的作用?/p> <p> </p> <p>四、架构设?/p> <p>如果需求做好的话,可以说这个品基本上能够得以出笼Q但是否U得上品质优UQ则看架构设计工作做的怎样了。一个好的品除了满_L业务功能外,q要满一些非功能性的需求:pȝ性能、可用性、可理性、可靠性、可扩展性、安全性等{?/p> <p>正是因ؓ面对q些众多问题Q在q一q程中,架构师很Ҏ走向极端。最常见的两U极端情况:Q?Q过分追求完。(2Q做出来pQ不考虑软g品质?/p> <p>作ؓ一个系l架构师Q很多hh完美M的們֐。他们不断的考虑pȝ的性能、可扩展性、安全性,技术的先进性等{。他们最喜欢说的的词Q组件性、通用性、扩展性等{。所以他们不断的修改架构Q不断的冒出新的思想Q采用新的技术。而这一切走向极端就会让研发陷入不可控制的地步。在我做物流和教育^C品的时候,都遇Cq样的问题。架构师希望产品做得更大Q满x多的业务需求,同时又希望几乎每个业务模块组件化Q具有更多的通用性,采用可能新的技术。最l造成计划的一拖再拖,让公叔R导层丧失信心?/p> <p>W二U情况在一些规模较的产品研发中也很常见。技术领gh在时间、资金或PM的压力下基本上放弃了软g品质的追求。他们只希望在规定的旉内尽快做Z个东西就行。他们基本上不太考虑lg性、扩展性等{。这样做出来的品和目也就差不多了Q因Z的通用性、扩充性太差?/p> <p>可以看出Q这两种情况都可能导致品的p|。第一UL想一口吃成一个胖子,他们忽略了Y件开发的跌代性,软gL在不断的跌代、更CQ螺旋式上升发展的。而第二种则是技术h员的悲哀Q他们没有条件去q求软g的品质,只能寄希望于产品的下一个版本。事实上Q没有前一个版本良好的框架Q新的版本要惛_好,几乎是重新开发?/p> <p>所以一个优U的架构师Q既要不攑ּ心中的完主义的理想Q又要对现实做一定程度的妥协Q在q种q中,领导团队q行技术开发。事实上Q在中国软g产业的现阶段Q急功q利的公司太多了Q他们不会提供更多的条g、更多的I间让架构师dC个优U的品。这是我们所有做软g技术h员的悲哀Q这是所有想走向、或正在架构师岗位上的h员的悲哀?/p> <p>在Y件品开发的q一阶段Q除了以上的情况Q还有许多问题同样会D产品的失败?/p> <p>例如公司对Y件工E的理解和掌握。Y件工E强调用过E来保证目的成功,一般都会提Z整套的理论,如一些核心流E、步骤、方法、规则等{,例如RUP,XP。有很多目l理、架构师和Y件公司的高层都希望去使用q些ҎQ以保证目、品的成功。特别是公司的上层领|他们只能通过q种Ҏ来保证对目的控Ӟ所以特别热衷于实施q些Ҏ。然而事实上呢?。大安常有q样的经历:Z文档而写文档Q写出来的文档基本上可以扔进垃圾,没有M作用了。我q样_q不认ؓ软g工程有什么不好,关键在于你怎么M用它。Y件工E是一门实跉|很强的学科Q需要我们根据不同的现实情况不断的调整、实施,而不是照本宣U的一些教条。最怕遇到这U情况:一些领导或目l理M几本软g工程的书Q自以ؓ扑ֈ了灵丹妙药,开始在目中强力实施。比如制订一些步骤、计划,在什么什么时_辑ֈ什么什么成果,要写什么什么样的文档等{。在我以前做教育软g产品中就充满了这U們֐。了在某Z旉交出架构设计文档Q我们大部分旉不是去考虑、验证架构,而是Z写出q䆾文档。结果是Q到我们要去实现Ӟ发现Ҏ行不通,整个架构存在严重的问题,到这个时候再回头重做设计Q代价太大了。个人感觉是Q要合理的用一些Y件工E理论,需要项目经理、架构师有丰富的实践l验Q能够根据不同的产品研发情况Q制订自q一些确实可行的Ҏ。Y件工E是一些通用的理论,从来而且应该是可以灵z裁减的?/p> <p>四、其他步?/p> <p>  如果说上面的步骤都很好的做到了,那品应该说基本上成功了。有了一个合理的的架构设计,那么详细设计和编码应该不是一个问题,q只需要我们的软g工程师的努力可以了。当然测试是很重要的Q但基本上不会导致品的研发p|?/p> <p>作者后讎ͼ在做q几个项目,l历q一些失败之后,我把自己的一些想法写下来。这文章文字比较ؕQ基本上惛_哪写到哪。我所到的问题,很多做Y件的朋友也时常碰刎ͼ在抱怨了太多之后Q我军_把它写下来。在国内做Y件太困难了,如果你对软gq有一些理想主义的话,那你太痛苦了?br /></p> <img src ="http://m.tkk7.com/zhanglijun33/aggbug/67429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/zhanglijun33/" target="_blank">无?/a> 2006-09-03 17:38 <a href="http://m.tkk7.com/zhanglijun33/archive/2006/09/03/acticle.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java模式学习(3)http://m.tkk7.com/zhanglijun33/archive/2006/07/25/adapter.html无?/dc:creator>无?/author>Tue, 25 Jul 2006 10:21:00 GMThttp://m.tkk7.com/zhanglijun33/archive/2006/07/25/adapter.htmlhttp://m.tkk7.com/zhanglijun33/comments/60037.htmlhttp://m.tkk7.com/zhanglijun33/archive/2006/07/25/adapter.html#Feedback2http://m.tkk7.com/zhanglijun33/comments/commentRss/60037.htmlhttp://m.tkk7.com/zhanglijun33/services/trackbacks/60037.html适配器模式可以把两个不相关的cȝ装在一起用。实际上是承和l合的综合运用?br />让我们来看一个例子:
public interface Itable{
public void say(String str);
}
public interface Ichair{
public void say(String str);
}
public class Table implements  Itable{
  public void say(String str){
    System.out.println(" i am a table :"+str);
  }
}
public class Chair implements Ichair{
  public void say(String str){
    System.out.println(" i am a chair :"+str);
  }
}

public class AdapterFitment  extends Table{
private Ichair c;
  public AdapterFitment(Ichair c){
  this.c=c;
}
public void insert(String str){c.say(str);}
}

然后呢,q个l合家具即能当桌子用又能当椅子用了?/span>


]]>
关于软g分层的讨?/title><link>http://m.tkk7.com/zhanglijun33/archive/2006/07/24/softlay.html</link><dc:creator>无?/dc:creator><author>无?/author><pubDate>Mon, 24 Jul 2006 08:02:00 GMT</pubDate><guid>http://m.tkk7.com/zhanglijun33/archive/2006/07/24/softlay.html</guid><wfw:comment>http://m.tkk7.com/zhanglijun33/comments/59834.html</wfw:comment><comments>http://m.tkk7.com/zhanglijun33/archive/2006/07/24/softlay.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://m.tkk7.com/zhanglijun33/comments/commentRss/59834.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/zhanglijun33/services/trackbacks/59834.html</trackback:ping><description><![CDATA[现在后台分成如下几个层:<br />DomainQ提供getter/setter<br />DaoQ接口,定义了持久化ҎQCRUD<br />DaoImplQDao的实?br />ServiceQ业务逻辑<br /><br />但是在实际的q程中发玎ͼservice里面有很多涉及到持久化的查询、更新操作,那么Q这些方法是在dao中定义呢Q还是在service中定义和实现Q?br />比如Q对于一?客户资料UserOrder 实体<br />dao中定义了getUserOrderByID() getAllUserOrder() insertUserOrder() updateUserOrder() delUserOrder()五个Ҏ<br />现在需要一?Ҏ地区查询客户getUserByArea()Q或?Ҏ产品U和地区查询客户 getUserByAreaSrv()<br />q样的方法,定义在serviceq是dao中?<br />W二个问题。service层肯定是面向客户端调用的Q那么dao层对于客L是否暴露Q?br />是_service层中是否提供dao中的ҎQ比如getAllUserOrder() insertUserOrder()q些ҎQ?br />如果不提供,那么客户端需要知道哪些是dao中提供的Q哪些是service提供?br />如果提供q些ҎQ意味着所有的Ҏ需要在dao中定义,daoimpl中实玎ͼservice中包装,是否太重复和烦琐Q?br />1.<br /><font face="Arial" size="2">DAO只负责数据库操作Q不涉及M逻辑QService需要业务逻辑了,比如getUserOrder()在DAOQ你查数据库就行,在service中,你可能需要首先验证当前用h否有q个操作权限Q然后调用DAOQ最后记录日?br />2.需要在dao中定义,daoimpl中实玎ͼservice中包装,是否太重复和烦琐Q?br />其实q不会发生,因ؓ你认为getUserByAreaSrv()Ҏ肯定一定要完全从数据库完成Q其实不Ӟ其实我可能只从数据库查询一个ID集合Q然后,在服务层再通过~存讉K装成完整的Model。这些都需要在Service完成Q只是一个比喻)?br /><br />预留Service是ؓ防止你的业务pȝ复杂化之后有一个插脚的地方?br /><br />现在很多pȝ没有这U插脚的地方Q在struts的Action中直接调用Hibernate数据库操作,如那个日本h做的开发框架RoR是q样Q这些以丧失可维护性做代h的快速开发都是伪框架?br /><br />所以,Z的系l将来留着Service<br />3.我认为Dao层还是不要暴露在最外层为妙Q即Service以外的层ơ都无法调用。否则实体化与应用逻辑以及界面之间的耦合度将无法控制Q导致品的生命周期~短Q可扩展性遭到破坏?br />Service层当然也可以有getUserOrderByID() q样的操作,但最好通过调用DAO来实玎ͼ或者像banq说的以dao-cache的方式来实现Q而不是直接去做实体操作。这样做可能会感掉有些重复繁琐,但会l品今后的升补充带来好处。可能会多出q?0Q的代码量,但带来的好处是v码能廉代码30Q的生命?br />Service的方法定义和Ҏ内的参数定义更倾于业务逻辑Q而不是存储方式。而Dao的定义则跟存储方式直接挂钩,而不需要过度考虑业务逻辑。所以代码上的“繁琐”恰C表了逻辑上的“简单”?br />更重要的是Service是必ȝ?br />22一般service层是怎么实现的?是不是就是一个拥有很多静态方法的c,每个静态方法处理一些业务逻辑Q还是有什么其它的ҎQ望指教 <br />1我还有疑问,比如CoreFeeService好像是操作CoreFeeq个domain bean的,如果我有一D业务逻辑Q是调用CoreFeeService改变CoreFee的一些属性,然后CoreFee持久化到数据库,接着可能要调用另一个domain bean的serviceҎ?br /><br />在Struts框架中,q段代码是写在Action中,q是别的地方QAction又好像应该只控制转发Q不应该有业务的代码在里面。但像上面那P可能q有事务处理Q这时我该怎么做好呢?<br />2你描q的q段设计本来是包含了业务逻辑。当然应该在Service里。service本n包含了粒度不同的操作Q粗_度的操作(ҎQ里可以包含很多l粒度的操作。这些细_度的操作可以是privateQ也可是是publicQ如果别的action需要它Q?br />Action的概念当然跟业务本n是有一定关pȝ。你可以在action的代码中表示Z些业务上的逻辑关系Q但要节U。能在service中实现的最好在service中。这对程序结构是有好处的?br />你说Q“Action又好像应该只控制转发Q不应该有业务的代码在里面”——这句话体现Z可能已经成ؓ“框架”的“受完”了。要用“框架”来提炼你的设计Q而不要用来约束你的思维。不要指望从“框架”中扑ֈ理清软g开发一切思\的“银弹”——因为它Ҏ不存在?br /></font><img src ="http://m.tkk7.com/zhanglijun33/aggbug/59834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/zhanglijun33/" target="_blank">无?/a> 2006-07-24 16:02 <a href="http://m.tkk7.com/zhanglijun33/archive/2006/07/24/softlay.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习设计模式(2)http://m.tkk7.com/zhanglijun33/archive/2006/07/24/partten2.html无?/dc:creator>无?/author>Mon, 24 Jul 2006 06:29:00 GMThttp://m.tkk7.com/zhanglijun33/archive/2006/07/24/partten2.htmlhttp://m.tkk7.com/zhanglijun33/comments/59801.htmlhttp://m.tkk7.com/zhanglijun33/archive/2006/07/24/partten2.html#Feedback1http://m.tkk7.com/zhanglijun33/comments/commentRss/59801.htmlhttp://m.tkk7.com/zhanglijun33/services/trackbacks/59801.html设计模式q不难,之所以把它列到j2ee学习的最后一,我想是因为它需要有很多写程序的体验。记得在一本书上看到程序员有三个特点(或者毛病)Q傲慢,懒惰QQw。其中最宝贵的品质是Q懒惎ͼ因ؓ他们/我们很懒Q所以对l常写一些重复的代码感觉烦躁Q从而不断(注意是不断地Q找ҎQ发明工h减轻他们/我们的负担(当然有时也是Z技术创斎ͼQ这样就出现了现在的局面,每天都有很多新技术、新框架涌现。好了,扯远了,下面来说一下另一个我们经常用到的模式--工厂模式?br />

设计模式?span lang="EN-US">Factory

定义:提供创徏对象的接?

Z使用?
工厂模式是我们最常用的模式了,著名的Jive论坛 ,大量用了工厂模式Q工厂模式在JavaE序pȝ可以说是随处可见?o:p>

Z么工厂模式是如此常用Q因为工厂模式就相当于创建实例对象的newQ我们经常要ҎcClass生成实例对象Q如A a=new A() 工厂模式也是用来创徏实例对象的,所以以后new时就要多个心|是否可以考虑实用工厂模式Q虽然这样做Q可能多做一些工作,但会l你pȝ带来更大的可扩展性和量的修改量?o:p>

我们以类SampleZQ?如果我们要创建Sample的实例对?

Sample sample=new Sample();

可是Q实际情冉|Q通常我们都要在创?span lang="EN-US">sample实例时做点初始化的工?比如赋?查询数据库等?o:p>

首先Q我们想到的是,可以使用Sample的构造函敎ͼq样生成实例写?

Sample sample=new Sample(参数);

但是Q如果创?span lang="EN-US">sample实例时所做的初始化工作不是象赋DL单的事,可能是很长一D代码,如果也写入构造函CQ那你的代码很难看了Q就需要Refactor重整Q?o:p>

Z么说代码很难看,初学者可能没有这U感觉,我们分析如下Q初始化工作如果是很长一D代码,说明要做的工作很多,很多工作装入一个方法中Q相当于很多鸡蛋放在一个篮子里Q是很危险的Q这也是有背?span lang="EN-US">Java面向对象的原则,面向对象的封?Encapsulation)和分z?Delegation)告诉我们Q尽量将长的代码分派“切剜y成每段Q将每段再“封装”v?减少D和D之间偶合联pL?Q这P׃风险分散,以后如果需要修改,只要更改每段Q不会再发生牵一动百的事情?o:p>

在本例中Q首先,我们需要将创徏实例的工作与使用实例的工作分开, 也就是说Q让创徏实例所需要的大量初始化工作从Sample的构造函C分离出去?o:p>

q时我们需?span lang="EN-US">Factory工厂模式来生成对象了Q不能再用上面简单new Sample(参数)。还?如果Sample有个l承如MySample, 按照面向接口~程,我们需要将Sample抽象成一个接?现在Sample是接?有两个子cMySample 和HisSample .我们要实例化他们?如下:

Sample mysample=new MySample();
Sample hissample=new HisSample();

随着目的深?span lang="EN-US">,Sample可能q会"生出很多儿子出来", 那么我们要对q些儿子一个个实例?更糟p的?可能q要对以前的代码q行修改:加入后来生出儿子的实?q在传统E序中是无法避免?

但如果你一开始就有意识用了工厂模式,q些ȝ没有了.

工厂Ҏ
你会建立一个专门生?span lang="EN-US">Sample实例的工?

public class Factory{

  public static Sample creator(int which){

  //getClass 产生Sample 一般可使用动态类装蝲装入cR?br />  if (which==1)
    return new SampleA();
  else if (which==2)
    return new SampleB();

  }

}

那么在你的程序中,如果要实例化Sample?׃?o:p>

Sample sampleA=Factory.creator(1);

q样,在整个就不涉及到Sample的具体子c?辑ֈ装效果,也就减少错误修改的机?q个原理可以用很通俗的话来比?是具体事情做得多,容易范错误.q每个做q具体工作的人都深有体会,相反,官做得越?说出的话抽象越W统,范错误可能性就少.好象我们从编E序中也能悟Zh生道?呵呵.

使用工厂Ҏ 要注意几个角Ԍ首先你要定义产品接口Q如上面?span lang="EN-US">Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factoryc,用来生成产品SampleQ如下图Q最双是生产的对象SampleQ?o:p>

q一步稍微复杂一点,是在工厂类上进行拓展,工厂cM有承它的实现类concreteFactory?b>?/i>

抽象工厂
工厂模式中有: 工厂Ҏ(Factory Method) 抽象工厂(Abstract Factory).

q两个模式区别在于需要创建对象的复杂E度上。如果我们创建对象的Ҏ变得复杂?span lang="EN-US">,如上面工厂方法中是创Z个对象Sample,如果我们q有新的产品接口Sample2.

q里假设Q?span lang="EN-US">Sample有两个concretecSampleA和SamleBQ而Sample2也有两个concretecSample2A和SampleB2

那么Q我们就上例中Factory变成抽象c?共同部分封装在抽象cM,不同部分使用子类实现Q下面就是将上例中的Factory拓展成抽象工?

public abstract class Factory{

  public abstract Sample creator();

  public abstract Sample2 creator(String name);

}

public class SimpleFactory extends Factory{

  public Sample creator(){
    .........
    return new SampleA
  }

  public Sample2 creator(String name){
    .........
    return new Sample2A
  }

}

public class BombFactory extends Factory{

  public Sample creator(){
    ......
    return new SampleB
  }

  public Sample2 creator(String name){
    ......
    return new Sample2B
  }

}

 

从上面看C个工厂各自生产出一?span lang="EN-US">Sample和Sample2,也许你会疑问Qؓ什么我不可以用两个工厂方法来分别生Sample和Sample2?

抽象工厂q有另外一个关键要点,是因?span lang="EN-US"> SimpleFactory内,生Sample和生产Sample2的方法之间有一定联p,所以才要将q两个方法捆l在一个类中,q个工厂cL其本w特征,也许刉过E是l一的,比如Q制造工艺比较简单,所以名U叫SimpleFactory?o:p>

在实际应用中Q工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,

举例

我们?span lang="EN-US">Jive的ForumFactoryZQ这个例子在前面的Singleton模式中我们讨Q现在再讨论其工厂模?

public abstract class ForumFactory {

  private static Object initLock = new Object();
  private static String className = "com.jivesoftware.forum.database.DbForumFactory";
  private static ForumFactory factory = null;

  public static ForumFactory getInstance(Authorization authorization) {
    //If no valid authorization passed in, return null.
    if (authorization == null) {
      return null;
    }
    //以下使用了Singleton 单态模?br />    if (factory == null) {
      synchronized(initLock) {
        if (factory == null) {
            ......

          try {
              //动态{载类
              Class c = Class.forName(className);
              factory = (ForumFactory)c.newInstance();
          }
          catch (Exception e) {
              return null;
          }
        }
      }
    }

    //Now, q回 proxy.用来限制授权对forum的访?br />    return new ForumFactoryProxy(authorization, factory,
                    factory.getPermissions(authorization));
  }

  //真正创徏forum的方法由l承forumfactory的子cd完成.
  public abstract Forum createForum(String name, String description)
  throws UnauthorizedException, ForumAlreadyExistsException;

  ....

}

 

 

因ؓ现在?span lang="EN-US">Jive是通过数据库系l存放论坛帖子等内容数据,如果希望更改为通过文gpȝ实现,q个工厂ҎForumFactory提供了提供动态接?

private static String className = "com.jivesoftware.forum.database.DbForumFactory";

你可以用自己开发的创徏forum的方法代替com.jivesoftware.forum.database.DbForumFactory可?

在上面的一D代码中一q了三U模?span lang="EN-US">,除了工厂模式?q有Singleton单态模?以及proxy模式,proxy模式主要用来授权用户对forum的访?因ؓ讉Kforum有两Uh:一个是注册用户 一个是游客guest,那么那么相应的权限就不一?而且q个权限是诏I整个系l的,因此建立一个proxy,cM|关的概?可以很好的达到这个效?  

看看Java宠物店中的CatalogDAOFactory:

public class CatalogDAOFactory {

  /**

  * 本方法制定一个特别的子类来实现DAO模式?br />  * 具体子类定义是在J2EE的部|描q器中?br />  */

  public static CatalogDAO getDAO() throws CatalogDAOSysException {

    CatalogDAO catDao = null;

    try {

      InitialContext ic = new InitialContext();
      //动态装入CATALOG_DAO_CLASS
      //可以定义自己的CATALOG_DAO_CLASSQ从而在无需变更太多代码
      //的前提下Q完成系l的巨大变更?o:p>

      String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS);

      catDao = (CatalogDAO) Class.forName(className).newInstance();

    } catch (NamingException ne) {

      throw new CatalogDAOSysException("
        CatalogDAOFactory.getDAO: NamingException while
          getting DAO type : \n" + ne.getMessage());

    } catch (Exception se) {

      throw new CatalogDAOSysException("
        CatalogDAOFactory.getDAO: Exception while getting
          DAO type : \n" + se.getMessage());

    }

    return catDao;

  }

}

CatalogDAOFactory是典型的工厂ҎQcatDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类Q这个实现子cdJava宠物店是用来操作catalog数据库,用户可以Ҏ数据库的cd不同Q定制自q具体实现子类Q将自己的子cdl与CATALOG_DAO_CLASS变量可以?o:p>

由此可见Q工厂方法确实ؓpȝl构提供了非常灵zd大的动态扩展机Ӟ只要我们更换一下具体的工厂ҎQ系l其他地Ҏ需一点变换,有可能系l功能进行改头换面的变化?span lang="EN-US">



]]>
q入设计模式的学习(1Q?/title><link>http://m.tkk7.com/zhanglijun33/archive/2006/07/24/parrten1.html</link><dc:creator>无?/dc:creator><author>无?/author><pubDate>Mon, 24 Jul 2006 06:07:00 GMT</pubDate><guid>http://m.tkk7.com/zhanglijun33/archive/2006/07/24/parrten1.html</guid><wfw:comment>http://m.tkk7.com/zhanglijun33/comments/59794.html</wfw:comment><comments>http://m.tkk7.com/zhanglijun33/archive/2006/07/24/parrten1.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/zhanglijun33/comments/commentRss/59794.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/zhanglijun33/services/trackbacks/59794.html</trackback:ping><description><![CDATA[学习设计模式应该是j2ee学习的最后阶D了。我知道自己的j2ee学的q不很扎实,但是工作中用C很多模式Q如果不把它们弄明白Q心里L个底Q学习可能L反复的吧。上个周末在国家图书馆里l于发现了一本不错的模式设计书。现在记录下学习q程Q以备后用?br />       设计模式的灵感来源于建筑学。一个年青的Ƨ洲建筑师发C同的建筑拥有不同的风|如果有意识的把这些风格的特征以不同的模式记录下来Q在以后的徏{设计之中就会很好的吸取Q承,发扬前h的设计经验。从而工作变得高效Q高质?br /><h3 style="TEXT-ALIGN: center" align="center">设计模式?span lang="EN-US">Singleton(单?<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span></h3><p><strong>定义</strong><span lang="EN-US">:<br />Singleton模式主要作用是保证在Java应用E序中,一个类Class只有一个实例存在?<o:p></o:p></span></p><p>在很多操作中Q比如徏立目?数据库连接都需要这L单线E操作?span lang="EN-US"><o:p></o:p></span></p><p>q有<span lang="EN-US">, singleton能够被状态化; q样Q多个单态类在一起就可以作ؓ一个状态仓库一样向外提供服务,比如Q你要论坛中的帖子计数器Q每ơ浏览一ơ需要计敎ͼ单态类能否保持住这个计敎ͼq且能synchronize的安全自动加1Q如果你要把q个数字怹保存到数据库Q你可以在不修改单态接口的情况下方便的做到?o:p></o:p></span></p><p>另外斚wQ?span lang="EN-US">Singleton也能够被无状态化。提供工h质的功能,<br /><br />Singleton模式׃ؓ我们提供了这样实现的可能。用Singleton的好处还在于可以节省内存Q因为它限制了实例的个数Q有利于Java垃圾回收Qgarbage collectionQ?br /><br />我们常常看到工厂模式中类装入?class loader)中也用Singleton模式实现?因ؓ被装入的cd际也属于资源?o:p></o:p></span></p><p><strong>如何使用<span lang="EN-US">?</span></strong><span lang="EN-US"><br />一般Singleton模式通常有几UŞ?<o:p></o:p></span></p><table style="WIDTH: 100%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="100%" border="0"><tbody><tr><td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: #cccccc; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt"><p><span lang="EN-US">public class Singleton {<o:p></o:p></span></p><p>  <span lang="EN-US">private Singleton(){}<o:p></o:p></span></p><p>  <span lang="EN-US">//在自己内部定义自׃个实例,是不是很奇怪?<br />  //注意q是private 只供内部调用<o:p></o:p></span></p><p>  <span lang="EN-US">private static Singleton instance = new Singleton();<o:p></o:p></span></p><p>  <span lang="EN-US">//q里提供了一个供外部讉K本class的静态方法,可以直接讉K  <br />  public static Singleton getInstance() {<br />    return instance;   <br />   } <br />} <o:p></o:p></span></p><p><span lang="EN-US"> <o:p></o:p></span></p></td></tr></tbody></table><p>W二UŞ?span lang="EN-US">:<o:p></o:p></span></p><table style="WIDTH: 100%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="100%" border="0"><tbody><tr><td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: #cccccc; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt"><p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 10.5pt">public class Singleton { <o:p></o:p></span></p><p>  <span lang="EN-US">private static Singleton instance = null;<br /><br />  public static synchronized Singleton getInstance() {<br /><br />  //q个Ҏ比上面有所改进Q不用每ơ都q行生成对象Q只是第一ơ     <br />  //使用时生成实例,提高了效率!<br />  if (instance==null)<br />    instanceQnew Singleton();<br />  return instance;   } <o:p></o:p></span></p><p><span lang="EN-US">} <o:p></o:p></span></p><p><span lang="EN-US"> <o:p></o:p></span></p></td></tr></tbody></table><p>使用<span lang="EN-US">Singleton.getInstance()可以讉K单态类?o:p></o:p></span></p><p>上面W二中Ş式是<span lang="EN-US">lazy initializationQ也是说第一ơ调用时初始SingletonQ以后就不用再生成了?o:p></o:p></span></p><p>注意?span lang="EN-US">lazy initialization形式中的synchronizedQ这个synchronized很重要,如果没有synchronizedQ那么用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论,有兴者进一步研I?o:p></o:p></span></p><p>一般认为第一UŞ式要更加安全些?span lang="EN-US"><o:p></o:p></span></p><p><strong>使用<span lang="EN-US">Singleton注意事项</span></strong>Q?span lang="EN-US"><br />有时在某些情况下Q用Singletonq不能达到Singleton的目的,如有多个Singleton对象同时被不同的c装入器装蝲Q在EJBq样的分布式pȝ中用也要注意这U情况,因ؓEJB是跨服务器,跨JVM的?o:p></o:p></span></p><p>我们?span lang="EN-US">SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocatorZE微分析一下:<br /><br />在Pet Store中ServiceLocator有两U,一个是EJB目录下;一个是WEB目录下,我们查这两个ServiceLocator会发现内容差不多Q都是提供EJB的查询定位服务,可是Z么要分开呢?仔细研究对这两种ServiceLocator才发现区别:在WEB中的ServiceLocator的采取Singleton模式QServiceLocator属于资源定位Q理所当然应该使用Singleton模式。但是在EJB中,Singleton模式已经失去作用Q所以ServiceLocator才分成两U,一U面向WEB服务的,一U是面向EJB服务的?o:p></o:p></span></p><p><span lang="EN-US">Singleton模式看v来简单,使用Ҏ也很方便Q但是真正用好,是非怸ҎQ需要对Java的类 U程 内存{概忉|相当的了解?o:p></o:p></span></p><p>q一步深入可参考:<span lang="EN-US"><o:p></o:p></span></p><p><span lang="EN-US"><a target="_blank">Double-checked locking and the Singleton pattern</a><o:p></o:p></span></p><p><span lang="EN-US"><a target="_blank">When is a singleton not a singleton?</a><o:p></o:p></span></p><img src ="http://m.tkk7.com/zhanglijun33/aggbug/59794.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/zhanglijun33/" target="_blank">无?/a> 2006-07-24 14:07 <a href="http://m.tkk7.com/zhanglijun33/archive/2006/07/24/parrten1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>架构webE序http://m.tkk7.com/zhanglijun33/archive/2006/07/05/zhanglijun33.html无?/dc:creator>无?/author>Wed, 05 Jul 2006 01:42:00 GMThttp://m.tkk7.com/zhanglijun33/archive/2006/07/05/zhanglijun33.htmlhttp://m.tkk7.com/zhanglijun33/comments/56648.htmlhttp://m.tkk7.com/zhanglijun33/archive/2006/07/05/zhanglijun33.html#Feedback6http://m.tkk7.com/zhanglijun33/comments/commentRss/56648.htmlhttp://m.tkk7.com/zhanglijun33/services/trackbacks/56648.html
q篇文章讨论怎样l合几个著名的框架去做到松耦合的目的,怎样建立你的构架Q怎样让你的各个应用层保持一致?br />  摘要:

  q篇文章讨论怎样l合几个著名的框架去做到松耦合的目的,怎样建立你的构架Q怎样让你的各个应用层保持一致。富于挑战的是:l合q些框架使得每一层都以一U松耦合的方式彼此沟通,而与底层的技术无兟뀂这文章将使用Q种行的开源框架来讨论l合框架的策?

  其实Q就用Java建造一个不是很烦琐的web应用E序Q也不是件轻杄事情。当Z个应用程序徏造一个构架时有许多事情需要考虑。从高层来说Q开发者需要考虑Q怎样建立用户接口Q在哪里处理业务逻辑Q和怎样持久化应用数据。这三层每一层都有它们各自的问题需要回{?各个层次应该使用什么技术?怎样才能把应用程序设计得松耦合和能灉|改变Q构架允许层的替换不会媄响到其它层吗Q应用程序怎样处理容器U的服务Q比如事务处理?

  当ؓ你的web应用E序创徏一个构架时Q需要涉及到相当多的问题。幸q的是,已经有不开发者已l遇到过q类重复发生的问题,q且建立了处理这c问题的框架。一个好框架具备以下几点Q?减轻开发者处理复杂的问题的负担(“不重复发明轮子”)Q内部定义ؓ可扩展的Q有一个强大的用户支持。框枉常能够很好的解决一斚w的问题。然而,你的应用E序有几个层可能都需要它们各自的框架。就如解决你的用h口(UIQ问题时你就不应该把事务逻辑和持久化逻辑掺杂q来。例如,你不应该在控制器里面写jdbc代码Q它包含有业务逻辑Q这不是控制器应该提供的功能。它应该是轻量的,代理来自用户接口QUIQ外的调用请求给其它服务于这些请求的应用层。好的框架自然的形成代码如何分布的指对{更重要的是Q框架减d发者从头开始写像持久层q样的代码的痛苦Q他们专注于对客户来说很重要的应用逻辑?br />
  q篇文章讨论怎样l合几个著名的框架去做到松耦合的目的,怎样建立你的构架Q怎样让你的各个应用层保持一致。富于挑战的是:l合q些框架使得每一层都以一U松耦合的方式彼此沟通,而与底层的技术无兟뀂这文章将使用Q种行的开源框架来讨论l合框架的策略。表现层我们用Struts;业务层我们将使用Spring;持久层用Hibrenate.你也可以在你的应用程序中替换q些框架中的M一U而得到同L效果。图Q展CZ当这些框架组合在一h从高层看是什么样子?



? 用Struts, Spring, ?Hibernate框架构徏的概?

  应用E序的分?/strong>

  大多C复杂的web应用都能被分成至4个各负其责的层次。这些层ơ是Q表现层、持久层、业务层、领域模型层。每层在应用E序中都有明的责QQ不应该和其它层h功能。每一应用层应该彼此独立但要给他们之间放一个通讯接口。让我们从审视各个层开始,讨论q些层应该提供什么和不应该提供什?/div>
  表现?/strong>

  在一个典型的web应用的一端是表现层。很多Java开发者也理解Struts所提供的。然而,太常见的是,他们把像业务逻辑之类的耦合的代码放q了一个org.apache.struts.Action。所以,让我们在像Strutsq样一个框架应该提供什么上取得一致意见。这儿是Struts负责的:

  ·为用L理请求和响应Q?
  ·提供一个控制器代理调用业务逻辑和其它上层处理;
  ·处理从其它层掷出l一个Struts Action的异常;
  ·为显C提供一个模型;
  ·执行用户接口验证?br />
  q儿是一些经常用Struts~写的但是却不应该和Struts表现层相伴的目Q?

  ·直接和数据库通讯Q比如JDBC调用Q?
  ·业务逻辑和与你的应用E序相关的验证;
  ·事务理Q?br />  ·在表现层中引入这U代码将D典型耦合和讨厌的l护?br />
  持久?/strong>

  在典型web应用的另一端是持久层。这通常是事情q速失控的地方。开发者低C构徏他们自己的持久层框架的挑战性。一般来_机构内部自己写的持久层不仅需要大量的开发时_而且q经常缺功能和变得难以控制。有几个开源的“对象-关系映射”框枉常解决问题。尤其是QHibernate框架为java提供了"对象Q关pL久化Q机制和查询服务。Hibernate寚w些已l熟悉了SQL和JDBC API的Java开发者有一个适中的学习曲UѝHibernate持久对象是基于简单旧式Java对象和Java集合。此外,使用Hibernateq不妨碍你正在用的IDE。下面的列表包含了你该写在一个持久层框架里的代码cdQ?br />
  查询相关的信息成为对象。Hibernate通过一U叫作HQL的面向对象的查询语言或者用条件表辑ּAPI来做q个事情?HQL非常cM于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。有一些新的专用的HQL语言成分要学Q不q,它们Ҏ理解而且文档做得好。HQL是一U用来查询对象的自然语aQ花很小的代价就能学习它?br />
  保存、更新、删除储存在数据库中的信息?

  像Hibernateq样的高U“对象-关系”映框架提供对大多CSQL数据库的支持Q它们支持“父/子”关pR事务处理、承和多态?br />
  q儿是一些应该在持久层里被避免的目Q?br />
  业务逻辑应该在你的应用的一个高一些的层次里。持久层里仅仅允许数据存取操作?

  你不应该把持久层逻辑和你的表现层逻辑搅在一赗避免像JSPs或基于servlet的类q些表现层组仉的逻辑和数据存取直接通讯。通过把持久层逻辑隔离q它自己的层Q应用程序变得易于修改而不会媄响在其它层的代码。例如:Hebernate能够被其它持久层框架或者API代替而不会修改在其它M层的代码?

  业务?/strong>

  在一个典型的web应用E序的中间的lg是业务层或服务层。从~码的视角来看,q个服务层是最Ҏ被忽视的一层。不隑֜用户接口层或者持久层里找到散布在其中的这U类型的代码。这不是正确的地方,因ؓq导致了应用E序的紧耦合Q这样一来,随着旉推移代码很隄护。幸好,针对q一问题有好几种Frameworks存在。在q个领域两个最行的框架是Spring和PicoContainerQ它们叫作微容器Q你可以不费力不费神的把你的对象q在一赗所有这些框枉工作在一个简单的叫作“依赖注入”(也通称“控制反转”)的概念上。这文章将着gSpring的ؓ指定的配|参数通过bean属性的setter注入的用。Spring也提供了一个构建器注入的复杂Ş式作为setter注入的一个替代。对象们被一个简单的XML文gq在一Pq个XML文g含有到像事务理器、对象工厂、包含业务逻辑的服务对象、和数据存取对象q些对象的引用?

  q篇文章的后面将用例子来把Spring使用q些概念的方法说得更清楚一些。业务层应该负责下面q些事情Q?br />
  ·处理应用E序的业务逻辑和业务验证;
  ·理事务Q?
  ·预留和其它层交互的接口;
  ·理业务层对象之间的依赖Q?
  ·增加在表现层和持久层之间的灵zL,使它们互不直接通讯Q?
  ·从表现层中提供一个上下文l业务层获得业务服务Q?
  ·理从业务逻辑到持久层的实现?

  领域模型?/strong>

  最后,因ؓ我们讨论的是一个不是很复杂的、基于web的应用程序,我们需要一l能在不同的层之间移动的对象。领域对象层由那些代表现实世界中的业务对象的对象们组成,比如Q一份订单、订单项、品等{。这个层让开发者停止徏立和l护不必要的数据传输对象Q或者叫作DTOsQ?来匹配他们的领域对象。例如,Hibernate允许你把数据库信息读q领域对象的一个对象图Q这样你可以在连接断开的情况下把这些数据显C到UI层。那些对象也能被更新和送回到持久层q在数据库里更新。而且Q你不必把对象{化成DTOsQ因为DTOs在不同的应用层间UdQ可能在转换中丢失。这个模型得Java开发者自然地以一U面向对象的风格和对象打交道Q没有附加的~码?br />
  l合一个简单的例子

  既然我们已经从一个高的层ơ上理解了这些组Ӟ 现在p我们开始实践吧。在q个例子中,我们q是合qStruts、Spring、Hibernate框架。每一个这些框架在一文章中都有太多的细节覆盖到。这文章将用一个简单的例子代码展示怎样把它们结合在一P而不是进入每个框架的许多l节。示例应用程序将C一个请求怎样跨越每一层被服务的。这个示例应用程序的一个用戯保存一个订单到数据库中和查看一个在数据库中存在的订单。进一步的增强可以使用h新或删除一个存在的订单?br />
  因ؓ领域对象和每一层交互,我们首先创建它们。这些对象将使我们定义什么应该被持久化,什么业务逻辑应该被提供,和哪U表现接口应该被设计。然后,我们配|持久层和用Hibernate为我们的领域对象定义“对?关系”映。然后,我们定义和配置我们的业务对象。在有了q些lg后,我们p讨论用Spring把这些层q在一赗最后,我们提供一个表现层Q它知道怎样和业务服务层交流和知道怎样处理从其它层产生的异常?br />
  领域对象?/strong>

  因ؓq些对象和所有层交互Q这也许是一个开始编码的好地斏V这个简单的领域模型包括一个代表一份订单的对象和一个代表一个订单项的对象。订单对象将和一l订单项对象有一对多的关pR例子代码在领域层有两个单的对象Q?br />
  ·com.meagle.bo.Order.java: 包括一份订单的概要信息Q?br />  ·com.meagle.bo.OrderLineItem.java: 包括一份订单的详细信息Q?br />
  考虑一下ؓ你的对象选择包名Q它反映你的应用程序是怎样分层的。例如:单应用的领域对象可以放进com.meagle.bo包。更多专门的领域对象放入在com.meagle.bo下面的子包里。业务逻辑在com.meagle.service包里开始打包,DAO对象放进com.meagle.service.dao.hibernate包。对于forms和actions的表现类分别攑օcom.meagle.action ?com.meagle.forms包。准的包命名ؓ你的cL供的功能提供一个清楚的区分Q当故障维护时更易于维护,和当l应用程序增加新的类或包时提供一致性?/div>
  持久层配|?/strong>

  用Hibernate讄持久层涉及到几个步骤。第一步是q行配置持久化我们的领域业务对象。因为我们用于领域对象持久化的Hibernate和POJOs一起工作,因此Q订单和订单对象包括的所有的字段的都需要提供getter和setterҎ。订单对象将包括像ID、用户名、合计、和订单这样一些字D늚标准的JavaBean格式的setter和getterҎ。订单项对象同L用JavaBean的格式ؓ它的字段讄setter和getterҎ?br />
  Hibernate在XML文g里映领域对象到关系数据库。订单和订单对象将有两个映文件来表达q种映射。有像XDocletq样的工h帮助q种映射。Hibernate映领域对象到q些文gQ?br />
  Order.hbm.xml
  OrderLineItem.hbm.xml

  你可以在WebContent/WEB-INF/classes/com/meagle/bo目录里找到这些生成的文g。配|Hibernate SessionFactory使它知道是在和哪个数据库通信Q用哪个数据源或连接池Q加载哪些持久对象。SessionFactory提供的Session对象是Java对象和像选取、保存、更新、删除对象这样一些持久化功能间的译接口。我们将在后面的部分讨论Hibernate操作Session对象需要的SessionFactory配置?br />
  业务层配|?/strong>

  既然我们已经有了领域对象Q我们需要有业务服务对象来执行应用逻辑、执行向持久层的调用、获得从用户接口层的h、处理事务、处理异常。ؓ了将所有这些连接v来ƈ且易于管理,我们用Spring框架的bean理斚w。Spring使用“控制反转?或者“setter依赖注入”来把这些对象连好,q些对象在一个外部的XML文g中被引用。“控制反转”是一个简单的概念Q它允许对象接受其它的在一个高一些的层次被创建的对象。用这U方法,你的对象从必d建其它对象中解放出来q低对象耦合?br />
  q儿是个不用IoC的对象创建它的从属对象的例子Q这D紧的对象耦合Q?br />


  ?Q没有用IoC的对象组l。对象A创徏对象Q和Q?br />
  q儿是一个用IoC的例子,它允许对象在一个高一些层ơ被创徏和传q另外的对象Q所以另外的对象能直接用现成的对象·Q译者注Q另外的对象不必再亲自创些要使用的对象]Q?br />

?Q对象用IoCl织。对象A包含setterҎQ它们接受到对象Q和Q的接口。这也可以用对象Q里的接受对象和E的构建器完成?/div>
  建立我们的业务服务对?/strong>

  我们在我们的业务对象中使用的setterҎ接受的是接口Q这些接口允许对象的松散定义的实玎ͼq些对象被讄或者注入。在我们q个例子里我们将使我们的业务服务对象接受一个DAOL制我们的领域对象的持久化。当我们在这文章的例子中用HibernateQ我们可以容易的转换C个不同的持久框架的实玎ͼ通知Spring使用新的实现的DAO对象。你能明白编E到接口和用“依赖注入”模式是怎样宽松耦合你的业务逻辑和你的持久化机制的?br />
  q儿是业务服务对象的接口Q它是一个DAO对象依赖的桩?br />
public interface IOrderService {
 public abstract Order saveNewOrder(Order order)
  throws OrderException,
      OrderMinimumAmountException;
 public abstract List findOrderByUser(String user)
              throws OrderException;
 public abstract Order findOrderById(int id)
              throws OrderException;
 public abstract void setOrderDAO(IOrderDAO orderDAO);
}

  注意上面的代码有一个ؓDAO对象准备的setterҎ。这儿没有一个getOrderDAOҎ因ؓ它不是必要的Q因Z太有从外面访问连着的OrderDAO对象的需要。DAO对象被用来和我们的持久层沟通。我们将用Spring把业务服务对象和DAO对象q在一赗因为我们编码到接口Q我们不会紧耦合实现?

  下一步是写我们的DAO实现对象。因为Spring有内建的对Hibernate的支持,q个例子DAO承HibernateDaoSupportc,q得我们容易取得一个到HibernateTemplatecȝ引用QHibernateTemplate是一个帮助类Q它能简化Hibernate Session的编码和处理HibernateExceptions。这儿是DAO的接口:

public interface IOrderDAO {
 public abstract Order findOrderById(final int id);
 public abstract List findOrdersPlaceByUser(final String placedBy);
 public abstract Order saveOrder(final Order order);
}

  我们q有两个对象要和我们的业务层q在一赗这包括HibernateSessionFactory和一个TransactionManager对象。这在Spring配置文g里直接完成。Spring提供一个HibernateTransactionManagerQ它从工厂l定一个Hibernate SessionC个线E来支持事务。这儿是HibernateSessionFactory和HibernateTransactionManager的Spring配置?

Qbean id="mySessionFactory"
    class="org.springframework.orm.hibernate.
       LocalSessionFactoryBean"Q?br /> Qproperty name="mappingResources"Q?
  QlistQ?
   QvalueQ?br />    com/meagle/bo/Order.hbm.xml
   Q?valueQ?br />   QvalueQ?br />    com/meagle/bo/OrderLineItem.hbm.xml
   Q?valueQ?br />  Q?listQ?br /> Q?propertyQ?br /> Qproperty name="hibernateProperties"Q?br />  QpropsQ?br />   Qprop key="hibernate.dialect"Q?br />    net.sf.hibernate.dialect.MySQLDialect
   Q?propQ?br />   Qprop key="hibernate.show_sql"Q?br />    false
   Q?propQ?br />   Qprop key="hibernate.proxool.xml"Q?br />    C:/MyWebApps/.../WEB-INF/proxool.xml
   Q?propQ?br />   Qprop key="hibernate.proxool.pool_alias"Q?br />     spring
   Q?propQ?br />  Q?propsQ?br /> Q?propertyQ?br />Q?beanQ?br />Q?-- Transaction manager for a single Hibernate
SessionFactory (alternative to JTA) --Q?br />Qbean id="myTransactionManager"
     class="org.
         springframework.
        orm.
        hibernate.
        HibernateTransactionManager"Q?br /> Qproperty name="sessionFactory"Q?br />  Qref local="mySessionFactory"/Q?br /> Q?propertyQ?br /> Q?beanQ?

  每一个对象能被Spring配置里的一个<beanQ标记引用。在q个例子里,bean “mySessionFactory”代表一个HibernateSessionFactoryQbean “myTransactionManager”代表一个Hibernate transaction manager。注意transactionManger bean有一个叫作sessionFactory的属性元素。HibernateTransactionManager有一个ؓsessionFactory准备的setter和getterҎQ它们是用来当Spring容器启动时的依赖注入。sessionFactory属性引用mySessionFactory bean。这两个对象现在当Spring容器初始化时被q在一赗这U连接把你从为引用和创徏q些对象而创建singleton对象和工厂中解放出来Q这减少了你应用E序中的代码l护。mySessionFactory bean有两个属性元?它们译成ؓmappingResources ?hibernatePropertes准备的setterҎ。通常Q如果你在Spring之外使用Hibernate,q个配置被保存在hibernate.cfg.xml文g中。不怎样,Spring提供了一个便L方式--在Spring配置文g中合qHibernate的配|?

  既然我们已经配置了我们的容器服务beans和把它们q在了一P我们需要把我们的业务服务对象和我们的DAO对象q在一赗然后,我们需要把q些对象q接C务管理器?br />
  q是在Spring配置文g里的样子Q?br />
Q?-- ORDER SERVICE --Q?
Qbean id="orderService"
 class="org.
     springframework.
     transaction.
     interceptor.
     TransactionProxyFactoryBean"Q?br /> Qproperty name="transactionManager"Q?br />  Qref local="myTransactionManager"/Q?br /> Q?propertyQ?br /> Qproperty name="target"Q?br />  Qref local="orderTarget"/Q?br /> Q?propertyQ?br /> Qproperty name="transactionAttributes"Q?br />  QpropsQ?br />   Qprop key="find*"Q?br />  PROPAGATION_REQUIRED,readOnly,-OrderException
   Q?propQ?br />   Qprop key="save*"Q?br />  PROPAGATION_REQUIRED,-OrderException
   Q?propQ?br />  Q?propsQ?br /> Q?propertyQ?br />Q?beanQ?br />Q?-- ORDER TARGET PRIMARY BUSINESS OBJECT:
Hibernate implementation --Q?br />Qbean id="orderTarget"
     class="com.
        meagle.
        service.
        spring.
        OrderServiceSpringImpl"Q?br /> Qproperty name="orderDAO"Q?br />  Qref local="orderDAO"/Q?br /> Q?propertyQ?br />Q?beanQ?br />Q?-- ORDER DAO OBJECT --Q?br />Qbean id="orderDAO"
     class="com.
        meagle.
        service.
        dao.
        hibernate.
        OrderHibernateDAO"Q?br /> Qproperty name="sessionFactory"Q?br />  Qref local="mySessionFactory"/Q?br /> Q?propertyQ?br />Q?beanQ?

  ?是我们已l连在一L东西的一个概览。它展示了每个对象是怎样相关联的和怎样被Spring讄q其它对象中。把q幅囑֒CZ应用中的Spring配置文gҎ查看它们之间的关pR?


?Q这是Spring怎样在q个配置的基上装配beans?br />
  q个例子使用一个TransactionProxyFactoryBeanQ它有一个ؓ我们已经定义了的事务理者准备的setterҎ。这是一个有用的对象Q它知道怎样处理声明的事务操作和你的服务对象。你可以通过transactionAttributes属性定义事务怎样被处理,transactionAttributes属性ؓҎ名定义模式和它们怎样参与q一个事务?br />
  TransactionProxyFactoryBeancM有一个ؓ一个target准备的setter,target是一个到我们的叫作orderTarget的业务服务对象的引用?orderTarget bean定义使用哪个业务服务对象q有一个指向setOrderDAO()的属性。orderDAO bean居于这个属性中QorderDAO bean是我们的和持久层交流的DAO对象?br />
  q有一个关于Spring和bean要注意的是bean能以两种模式工作。这两种模式被定义ؓsingleton和prototype。一个bean默认的模式是singletonQ意味着一个共享的bean的实例将被管理。这是用于无状态操?-像一个无状态会话bean提供的那样。当bean由Spring提供Ӟprototype模式允许创徏bean的新实例。你应当只有在每一个用户都需要他们自qbean的拷贝时才用prototype模式?br />提供一个服务定位器

  既然我们已经把我们的服务和我们的DAOqv来了Q我们需要把我们的服务暴露给其它层。通常是一个像使用Struts或Swingq样的用h口层里的代码来用这个服务。一个简单的处理Ҏ是用一个服务定位器模式的类从一个Spring上下文中q回资源。这也可以靠引用bean ID通过Spring来直接完成?br />
  q儿是一个在Struts Action中怎样配置一个服务定位器的例子:
public abstract class BaseAction extends Action {
 private IOrderService orderService;
 public void setServlet(ActionServlet
                 actionServlet) {
  super.setServlet(actionServlet);
  ServletContext servletContext =
        actionServlet.getServletContext();
  WebApplicationContext wac =
   WebApplicationContextUtils.
     getRequiredWebApplicationContext(
                 servletContext);
   this.orderService = (IOrderService)
           wac.getBean("orderService");
 }
 protected IOrderService getOrderService() {
  return orderService;
 }
}

  用户接口层配|?/strong>

  CZ应用的用h口层使用Struts框架。这儿我们将讨论当ؓ一个应用分层时和Struts相关的部分。让我们从在struts-config.xml文g里检查一个Action配置开始?br />
Qaction path="/SaveNewOrder"
  type="com.meagle.action.SaveOrderAction"
  name="OrderForm"
  scope="request"
  validate="true"
  input="/NewOrder.jsp"Q?br /> Qdisplay-nameQSave New OrderQ?display-nameQ?br /> Qexception key="error.order.save"
  path="/NewOrder.jsp"
  scope="request"
  type="com.meagle.exception.OrderException"/Q?br /> Qexception key="error.order.not.enough.money"
  path="/NewOrder.jsp"
  scope="request"
  type="com.
  meagle.
  exception.
  OrderMinimumAmountException"/Q?br /> Qforward name="success" path="/ViewOrder.jsp"/Q?br /> Qforward name="failure" path="/NewOrder.jsp"/Q?br />Q?actionQ?br />

  SaveNewOrder Action被用来持久化一个用户从用户接口层提交的订单。这是一个典型的Struts ActionQ然而,注意q个action的异帔R|。这些Exceptions为我们的业务服务对象也在Spring 配置文g中配|了。当q些异常被从业务层掷出我们能在我们的用户接口里恰当的处理它们。第一个异常,OrderExceptionQ当在持久层里保存订单对象失败时被q个action使用。这引起事务回滚和通过业务对象传递把异常传回lStruts层。OrderMinimumAmountExceptionQ在业务对象逻辑里的一个事务因为提交的订单达不到最订单数量而失败也被处理。然后,事务回滚和q个异常能被用户接口层恰当的处理?

  最后一个连接步骤是使我们的表现层和我们的业务层交互。这已经通过使用前面讨论的服务定位器来完成了。服务层充当一个到我们的业务逻辑和持久层的接口。这儿是 Struts中的SaveNewOrder Action可能怎样使用一个服务定位器调用一个业务方法:

public ActionForward execute(
 ActionMapping mapping,
 ActionForm form,
 javax.servlet.http.HttpServletRequest request,
 javax.servlet.http.HttpServletResponse response)
 throws java.lang.Exception {
 OrderForm oForm = (OrderForm)form;
 // Use the form to build an Order object that
 // can be saved in the persistence layer.
 // See the full source code in the sample app.
 // Obtain the wired business service object
 // from the service locator configuration
 // in BaseAction.
 // Delegate the save to the service layer and
 // further upstream to save the Order object.
 getOrderService().saveNewOrder(order);
 oForm.setOrder(order);
 ActionMessages messages = new ActionMessages();
 messages.add(
   ActionMessages.GLOBAL_MESSAGE,
new ActionMessage(
   "message.order.saved.successfully"));
 saveMessages(request, messages);
 return mapping.findForward("success");
}

  l论

  q篇文章按照技术和架构覆盖了许多话题。从中而取出的主要思想是怎样更好的给你的应用E序分层Q用h口层、持久逻辑层、和其它M你需要的应用层。这样可以解耦你的代码,允许d新的代码lgQ你的应用在将来更易维护。这里覆盖的技术能很好的解册cȝ问题。不怎样Q用这L构架可以让你用其他技术代替现在的层。例如,你也怸想用Hibernate持久化。因Z在你的DAO对象中编码到接口Q你能怎样使用其它的技术或框架Q比?iBATISQ作Z个替代是显而易见的。或者你可能用不同于Struts的框架替代你的UI层。改变UI层的实现不会直接影响你的业务逻辑层或者你的持久层。替换你的持久层不会影响你的UI逻辑或业务服务层。集成一个web应用其实也不是一件烦琐的工作Q靠解耦你的各应用层和用适当的框架组成它Q它能变得更Ҏ处理


]]> վ֩ģ壺 ҹƵվ| ˸Ƶ| ؼëƬ| ޻Ƭֻѹۿ| ҹƷһ| ھƷһëƬѿ| 84paoƵѲ| һƷһAVһи| ɫ͵͵ݺۺ| þù޾Ʒ| ݺady޾Ʒ| һ| ձ˳ɻҳۿƵ| һɫþۺ޾Ʒ| ޹Ʒ߹ۿ97| ѹۿվ| ۺƵ| ˳Ƶ߹ۿ| ѹվ߹ۿ| ޳aһ| avƷר߹ۿ| ˾ƷƵȫ| Ļѹۿַ | 鶹69Ƶ| aѹۿ| ޾Ʒ߳ˮ| һëƬѹۿƵ| 3344ѲŹۿƵ| ˳ͼƬС˵վ| Ůۺɫһ | ޳avƬþ| ɫ| aٰƵ| ߹ۿ޾Ʒ| Ʒۺ| ƷԴѹۿ| ƷպAV| 뾫ƷA߹ۿ| ϵйƷƷ˿| 99ƷƵѹۿ| þþþŷղAV|