??xml version="1.0" encoding="utf-8" standalone="yes"?> 转自Liu Hang 软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>
一、Y件品的立项 一个Y件品的开发和目有着许多不同Q一般来_软g目(project)都是因ؓ有了明确的客P或者已l有了合同或意向而开始启动的。Y件?product)则完全不一样了。在一个品没有开发出来之前,基本上没有客戗当然也有h仅仅凭着一套大脑中的想法或概念p扑ֈ客户Q对q些人我只有佩服。当然大多数公司只能先拿Z套自q产品L销Q才有可能找到定单。所以就有了做品的x?/p>
在这些Y件公怸又可以分两种情况。一U是在某个行业做了多个项目,也积累了一些行业、技术等l验。每一个新的项目都要重复很多同L工作Q效率自然不高了。这时公司很自然的想到要有自q产品。于是开始品的立项了?/p>
另外一U公司则完全不是q样。他们不是在某个行业做过多少目Q甚x本没有做q一个项目,p雄心勃勃的去做品。这U情冉|天都在发生。他们以前可能做pȝ集成的,可能卖硬件的Q或许根本就不是IT行业的,或者恰好做了一个项目,现在他们要进军Y件行业了Q所以急切的要做出自己的品去打市场。于是他们在一番调查论证后Q开始了产品的立V?/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>
无论哪种公司Q他们在做品立Ҏ都要做好以下的心里准备: ? 软g产品开发投资是很大的,特别是对哪些惛_大型的、优U产品的公司?/p>
? 软g产品开发周期也是比较长的。两、三q做一个品是很常见的。不要认为半q就可以做一个很好的产品 ? 软g产品是很Ҏp|的。既有可能品开发不出来Q也有可能没有市场?/p>
如果一个公司没有这些心里准备,那结果就很可能失败。ؓ什么这么说Q以我的亲nl历来说吧。我曄做过的一家公司,主要业务是做pȝ集成的。后来开始了一个物Y件的产品开发。在2000q左叻I物流行业软g刚刚兴vQ也是一个比较好的方向。公司组Z一个开发团队,开始了长达两年的曲折的研发q程。由于在研发q程中遇到的U种问题Q无法给公司领导层一个明的l果Q在研发开始初见曙光的时候,公司高层l止了这个品。公司的高层忍受不了大量的投资和q长的时间。Q何想做品的公司都一定要有这些心里准备,要充分估计投资额和研发周期?/p>
假设公司l过了充分的Q也有了一定的投资和时间预,产品立项了。但q只是一个良好的开端,因ؓ下面的Q何一个过E的p|Q都有可能导致全盘皆输?/p>
二、团队构?/p>
产品立项后,p开始组建研发团队了。Y件开发是一个既要高度协作、又有独立创造的智力zd。所以h的因素是关系C品开发能否成功的一个重要方面。应该说产品能否研发成功Q研发团队的合理构徏是关键性的。一个公司的领导层或许没有多Y件研发的l验Q但必须要保证能构徏一个合理的研发团队。就点很Ҏ理解Q就是让合适的人去做合适的事。不q反q来_如果领导层没有Y件研发的l验Q那也很难构Z个合理的团队。那怎样构徏一个好的团队呢Q这个问题没有一个非常普遍的{案。各个品的规模、技术难度都不相同,{案也不一栗?/p>
我们时常看到的情冉|Q公怼d一个研发经理或叫PM,负责整个研发q程。于是问题就出来了。这个PM是负责管理工作还是技术工作,或者两个都一赯责?怎样规定PM的职责权限?如果没有对这个问题的明确{案Q那危险随之而来的。就来我的经历过的来说吧?/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>
q样的故事每天都在发生,大量的技术h员在抱怨领g懂技术,瞎指挥。在我的案例中,可以明显的感觉到Q公司对q个PM没有明确的职责划分,或者这个PM没有摆正自己的位|。这个PM应该做做理工作Q而不是负责技术?/p>
做Y件开发的都知道,一个团队中一般都有一个技术领|或者叫架构师(ArchitectQ?那他和PM怎样划分职责Q? 如果要开发的产品规模比较大,比如人员数达?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>
对于开发的产品规模较小Q也可以完全不设|专职的PM。设|一位Team LeaderQ他既负责整个技术、也同时负责团队的管理工作。如果认担较重的话,可以为Team Leader配置一位秘书(目理人员Q,他的主要功能是辅助Team Leader做一些管理方便的工作。如人员招聘的准备工作、开发计划的监督{等?/p>
当团队合理的构徏之后Q下面的p入了产品研发的核心流E了?/p>
三、业务徏?amp;需求分? 前面的过E更多的是由企业领导层决定的Q当我们技术h员进入这个团队时Q只能祈讨已l有了一个好的开始:公司下定军_要研发这个品,有一个优U的、明白自p责的PM。现在已及下面的所有流E都和技术h员(包括需求h员)密切相关Q是技术h员决定着产品成|与否的时候了?/p>
无论做品还是项目,W一步做需求分析,q一Ҏȝ疑。几乎每一个做软g的都知道Q需求的重要性。可是ؓ什么那么多的品或目最后失败的主要原因是需求问题呢Q?/p>
在Y件研发中Q品的业务需求比目的业务需求更难以定。品一般面对的是某个行业的通用需求,涉及的客户面更广Q合理的提取q些需求以形成更通用的品本w就是一件很困难的工作。对于一些以前没有这些行业经验的软g公司来说Q这更困难了。很多公司真因ؓ没有很好d需求分析的工作而导致品的p|。在我以前做物流的那家公叔RQ也是犯了这样严重的错误。我们当时对物流行业q不熟悉Q也不能很好的把握业务需求,产品研发在来回反复的q程中消耗了大量的时间与_֊?/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>
也有很多公司没有业务专家Q而把q个角色附加l架构师了。他们要求架构师既要_N业务,也要_N技术。而现实中Q这L人凤毛麟角,属于可遇而不可求的那一cR所以在q类角色没有很明分开的品研发中Q得到的东西要么是需求方面做得不够好Q要么在软g架构斚w不o人满意?/p>
怎样最大程度保证需求的合理Q我个h认ؓ做一个品的界面原型是一个好的方法。这一点在做一个基于browser的应用系l时更可行:Ҏ业务需求做出整个的面原型Q这L面也许很粗p,后台也不需要Q何的E序q行Q但可以Ҏq些面元素及之间的程来验证业务需求是否合理、正。这U方法应用到目开发(相对于品)中,可以和客户一起验证需求,l过几次反复Q可以比较准的理解、把握客L真实需求。这L工作耗费旉不多Q但却能起到很大的作用?/p>
四、架构设?/p>
如果需求做好的话,可以说这个品基本上能够得以出笼Q但是否U得上品质优UQ则看架构设计工作做的怎样了。一个好的品除了满_L业务功能外,q要满一些非功能性的需求:pȝ性能、可用性、可理性、可靠性、可扩展性、安全性等{?/p>
正是因ؓ面对q些众多问题Q在q一q程中,架构师很Ҏ走向极端。最常见的两U极端情况:Q?Q过分追求完。(2Q做出来pQ不考虑软g品质?/p>
作ؓ一个系l架构师Q很多hh完美M的們。他们不断的考虑pȝ的性能、可扩展性、安全性,技术的先进性等{。他们最喜欢说的的词Q组件性、通用性、扩展性等{。所以他们不断的修改架构Q不断的冒出新的思想Q采用新的技术。而这一切走向极端就会让研发陷入不可控制的地步。在我做物流和教育^C品的时候,都遇Cq样的问题。架构师希望产品做得更大Q满x多的业务需求,同时又希望几乎每个业务模块组件化Q具有更多的通用性,采用可能新的技术。最l造成计划的一拖再拖,让公叔R导层丧失信心?/p>
W二U情况在一些规模较的产品研发中也很常见。技术领gh在时间、资金或PM的压力下基本上放弃了软g品质的追求。他们只希望在规定的旉内尽快做Z个东西就行。他们基本上不太考虑lg性、扩展性等{。这样做出来的品和目也就差不多了Q因Z的通用性、扩充性太差?/p>
可以看出Q这两种情况都可能导致品的p|。第一UL想一口吃成一个胖子,他们忽略了Y件开发的跌代性,软gL在不断的跌代、更CQ螺旋式上升发展的。而第二种则是技术h员的悲哀Q他们没有条件去q求软g的品质,只能寄希望于产品的下一个版本。事实上Q没有前一个版本良好的框架Q新的版本要惛_好,几乎是重新开发?/p>
所以一个优U的架构师Q既要不攑ּ心中的完主义的理想Q又要对现实做一定程度的妥协Q在q种q中,领导团队q行技术开发。事实上Q在中国软g产业的现阶段Q急功q利的公司太多了Q他们不会提供更多的条g、更多的I间让架构师dC个优U的品。这是我们所有做软g技术h员的悲哀Q这是所有想走向、或正在架构师岗位上的h员的悲哀?/p>
在Y件品开发的q一阶段Q除了以上的情况Q还有许多问题同样会D产品的失败?/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>
如果说上面的步骤都很好的做到了,那品应该说基本上成功了。有了一个合理的的架构设计,那么详细设计和编码应该不是一个问题,q只需要我们的软g工程师的努力可以了。当然测试是很重要的Q但基本上不会导致品的研发p|?/p>
作者后讎ͼ在做q几个项目,l历q一些失败之后,我把自己的一些想法写下来。这文章文字比较ؕQ基本上惛_哪写到哪。我所到的问题,很多做Y件的朋友也时常碰刎ͼ在抱怨了太多之后Q我军_把它写下来。在国内做Y件太困难了,如果你对软gq有一些理想主义的话,那你太痛苦了?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>
]]>
DaoQ接口,定义了持久化ҎQCRUD
DaoImplQDao的实?br />ServiceQ业务逻辑
但是在实际的q程中发玎ͼservice里面有很多涉及到持久化的查询、更新操作,那么Q这些方法是在dao中定义呢Q还是在service中定义和实现Q?br />比如Q对于一?客户资料UserOrder 实体
dao中定义了getUserOrderByID() getAllUserOrder() insertUserOrder() updateUserOrder() delUserOrder()五个Ҏ
现在需要一?Ҏ地区查询客户getUserByArea()Q或?Ҏ产品U和地区查询客户 getUserByAreaSrv()
q样的方法,定义在serviceq是dao中?
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.
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 />
预留Service是ؓ防止你的业务pȝ复杂化之后有一个插脚的地方?br />
现在很多pȝ没有这U插脚的地方Q在struts的Action中直接调用Hibernate数据库操作,如那个日本h做的开发框架RoR是q样Q这些以丧失可维护性做代h的快速开发都是伪框架?br />
所以,Z的系l将来留着Service
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望指教
1我还有疑问,比如CoreFeeService好像是操作CoreFeeq个domain bean的,如果我有一D业务逻辑Q是调用CoreFeeService改变CoreFee的一些属性,然后CoreFee持久化到数据库,接着可能要调用另一个domain bean的serviceҎ?br />
在Struts框架中,q段代码是写在Action中,q是别的地方QAction又好像应该只控制转发Q不应该有业务的代码在里面。但像上面那P可能q有事务处理Q这时我该怎么做好呢?
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 />
]]>
定义:提供创徏对象的接?
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) }
} |
那么在你的程序中,如果要实例化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(){ public Sample2 creator(String name){
}
public class BombFactory extends Factory{ public Sample creator(){ public Sample2 creator(String name){
}
|
从上面看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(); public static ForumFactory getInstance(Authorization authorization) { try { //Now, q回 proxy.用来限制授权对forum的访?br /> return new ForumFactoryProxy(authorization, factory, //真正创徏forum的方法由l承forumfactory的子cd完成. ....
}
|
因ؓ现在?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(); String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS); catDao = (CatalogDAO) Class.forName(className).newInstance(); } catch (NamingException ne) { throw new CatalogDAOSysException(" } catch (Exception se) { throw new CatalogDAOSysException(" } 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">
定义:
Singleton模式主要作用是保证在Java应用E序中,一个类Class只有一个实例存在?
在很多操作中Q比如徏立目?数据库连接都需要这L单线E操作?span lang="EN-US">
q有, singleton能够被状态化; q样Q多个单态类在一起就可以作ؓ一个状态仓库一样向外提供服务,比如Q你要论坛中的帖子计数器Q每ơ浏览一ơ需要计敎ͼ单态类能否保持住这个计敎ͼq且能synchronize的安全自动加1Q如果你要把q个数字怹保存到数据库Q你可以在不修改单态接口的情况下方便的做到?o:p>
另外斚wQ?span lang="EN-US">Singleton也能够被无状态化。提供工h质的功能,
Singleton模式׃ؓ我们提供了这样实现的可能。用Singleton的好处还在于可以节省内存Q因为它限制了实例的个数Q有利于Java垃圾回收Qgarbage collectionQ?br />
我们常常看到工厂模式中类装入?class loader)中也用Singleton模式实现?因ؓ被装入的cd际也属于资源?o:p>
如何使用?
一般Singleton模式通常有几UŞ?
public class Singleton { private Singleton(){} //在自己内部定义自׃个实例,是不是很奇怪? private static Singleton instance = new Singleton(); //q里提供了一个供外部讉K本class的静态方法,可以直接讉K |
W二UŞ?span lang="EN-US">:
public class Singleton { private static Singleton instance = null; } |
使用Singleton.getInstance()可以讉K单态类?o:p>
上面W二中Ş式是lazy initializationQ也是说第一ơ调用时初始SingletonQ以后就不用再生成了?o:p>
注意?span lang="EN-US">lazy initialization形式中的synchronizedQ这个synchronized很重要,如果没有synchronizedQ那么用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论,有兴者进一步研I?o:p>
一般认为第一UŞ式要更加安全些?span lang="EN-US">
使用Singleton注意事项Q?span lang="EN-US">
有时在某些情况下Q用Singletonq不能达到Singleton的目的,如有多个Singleton对象同时被不同的c装入器装蝲Q在EJBq样的分布式pȝ中用也要注意这U情况,因ؓEJB是跨服务器,跨JVM的?o:p>
我们?span lang="EN-US">SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocatorZE微分析一下:
在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>
Singleton模式看v来简单,使用Ҏ也很方便Q但是真正用好,是非怸ҎQ需要对Java的类 U程 内存{概忉|相当的了解?o:p>
q一步深入可参考:
Double-checked locking and the Singleton pattern
When is a singleton not a singleton?
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); } |
public interface IOrderDAO { public abstract Order findOrderById(final int id); public abstract List findOrdersPlaceByUser(final String placedBy); public abstract Order saveOrder(final Order order); } |
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? |
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? |
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; } } |
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 /> |
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"); } |