﻿<?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-study-随笔分类-面向对象设计模式</title><link>http://www.blogjava.net/xixidabao/category/24797.html</link><description>GROW WITH JAVA</description><language>zh-cn</language><lastBuildDate>Sat, 26 Jan 2008 10:57:53 GMT</lastBuildDate><pubDate>Sat, 26 Jan 2008 10:57:53 GMT</pubDate><ttl>60</ttl><item><title>职场新人必看：如何在三个月掌握三年的经验（转载)</title><link>http://www.blogjava.net/xixidabao/archive/2008/01/26/177926.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sat, 26 Jan 2008 08:17:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2008/01/26/177926.html</guid><description><![CDATA[很多资料在网上都是可以找到的，只是看你具备不具备足够的信息收集与处理能力，而这个收集与处理信息的过程，也能极大的提升你的职业能力。 <br />
<br />
　　我一直有个感觉，在&#8220;模仿中成长，在创新中成功&#8221;，其实在真正的职业工作中，大多数的工作都是模仿重复，强调的是工作效率，而不是创新。对于企业而言，过度的创新必然导致过多的失败，以及效率的低下。 <br />
<br />
　　以下方式是我的成长中曾经做过的，也是我用来训练新员工的方案。你们也可以试试。 <br />
<br />
　　看到很多谈应聘技巧的帖子，其实并不实用，有菜谱并不代表能做出好菜，能不能做出好菜仍要看你天天炒，日日炒，炒出来的本事。 <br />
<br />
　　所以，我这里要强调的一点是，你收集到的任何资料都不能只是看看，而必须自己手把手，动手去整理、去归类，去建立新的结构，这个信息收集与处理的过程甚至比你最后总结成文的文字更重要。 <br />
<br />
　　何谓&#8220;学习&#8221;？学习学习，学而习，习而成习惯。光学不习，那知识还只是书上的，老师教的，不是你自己的，只有你重复练习了，经过量变，才会有质变，当你形成条件反射时，你就真正掌握这个东西了。 <br />
<br />
　　这个过程需要维持两至三个月的时间，一定要坚持下去，你会看到自己的变化的。否则，你会用你最青春的两三年来慢慢沉淀出这些你两三个月就能掌握的东西。 <br />
<br />
　　一切一切，其实，你们比的不是其它的东西，只是比的速度。 <br />
<br />
　　这也是为什么我那么强调基本功的原因。 <br />
　　　　 <br />
　　　　 <br />
　　　　1. 职业分析： <br />
　　　　A. 分析性格——分析长处和短处——分析大家都有的长处——确定自己最终发展的专业 <br />
　　　　B. 确定兴趣——分析竞争的激烈程度和发展的空间大小——寻找相对优势—确定自己最终进入的行业 <br />
　　　　C. 确定行业内自己的专业方向，继续保持自身的专业优势。 <br />
　　　　 /* 性格决定专业，兴趣决定行业，行业&gt;专业，某个行业会包括很多专业。 */ <br />
<br />
　　　　2. 编写行业报告——着重对行业全面性的把握。 <br />
　　　　A. 通过上网查询和购买行业报刊，收集不少于三十万字的行业、重点企业的有效资料，在电脑中进行资料分析、分类、汇总。 <br />
　　　　B. 参考同类行业书籍，确定写作提纲，确定文章结构和逻辑方向，培养文字表达能力和逻辑能力，以及熟练的电脑使用技能。 <br />
　　　　C. 将三十万字资料浓缩成十至十五万字，写成一本符合出版行文格式要求的行业报告。如果选题好，还真的有出版的可能性。如果有一定的独特见解，也可以写成文章争取在专业刊物上发表，树立个人专业形象。 <br />
　　　　 <br />
　　　　3. 编写讲座报告——着重对专业系统性的把握。 <br />
　　　　A. 根据你希望从事的专业岗位，从报告中选择两到三个重点，将书稿压缩成两万字的讲座稿（按每分钟150字的演讲速度，即两个小时）。 <br />
　　　　B. 将演讲稿再浓缩成两千字的提纲和重要内容，使用PPT软件编成演讲用演示文件，并根据相关内容配以精彩图片。 <br />
　　　　C. 培养职业化的公众表达能力和表达方式，练习普通话，使用讲座稿进行互动讲座和演讲练习，只到脱口而出。 <br />
　　　　 <br />
<br />
　　告诉大家两个名人是这么成长的． <br />
　　 <br />
　　一个是教英语的李阳，他读大学时成绩不好，英语不及格，然后他做什么去了？他跑到没人的地方大声喊英语去了． <br />
　　 <br />
　　一个是做广告的叶茂中，他卖广告卖不出去了，他跑回家写书．别人看到的和他自己说的是拿着书出版出了名，发达了．其实做过这个事的人才会知道，当他把这本书写出来时，能不能出版已经不重要的，因为他知道他变化了． <br />
　　 <br />
　　我当时也是没办法了，把所有的钱买了台电脑，在家里做了三个月这个事，三个月后的变化是惊人的，我的父母、我兼职的公司的老总，最重要的是我自己，都感觉到了自己的变化。 <br />
　　 <br />
　　完全不同了。 <br />
<br />
　　其实我写的已经不是理论了，其实什么都没有技巧的，只是多看书，然后多做，硬磕，坚持下去，刚开始觉得没变化，没感觉，很累，坚持不下去，然后做着做着，就越来越快了，然后慢慢的有变化． <br />
<br />
　　而且有意思的是，我在家呆了三个月，做的事其实根本与我所从事的工作没有一点关系．只是这三个月的训练，对于我的逻辑、结构、全局性、文字表达能力、口头表达能力有了极大的提升。 <br />
<br />
　　至于收入翻５翻，当年一个月也就八百块钱，然后做完这个训练后整个人的状态都变了，有自信了，然后写了一个方案去应聘，结果进了一家大公司，当然，开始我还不想去，因为对方只给我800/月，还要自己租房子，吃饭，觉得不好，但是对方连续四个月三次打电话找我，于是我去了，结果去了就后悔了，真正好的公司根本不在乎工资的，重要的是你自己的能力。第一个月，我就挣了八千块，我以前想都不敢想的。然后两个月就转了正，而有一个有关系的同事，呆了一年还没能转正。然后每个月的收入超过工资几倍，还有年终奖两万，出国旅游，其实也不累，我到这个家公司的同时，还到另一家广告公司兼职，呵呵，很回忆的过去。 <br />
<br />
　　现在看到太多的人谈工资，我确实不喜欢，我这几年都不和老板谈工资的，因为说出来好笑，帐面工资高了，还要多扣税． <br />
<br />
　　我只在意公司的分配方式，怎么样算提成和奖金，年薪． <br />
　　 <br />
　　上个月有一个和我同龄的名牌大学MBA来我现在所在的小公司应聘,不愿意和人事小姐谈,老板不在,我就来谈了,我说好呀,以你的资历我不能和你谈给谁做副手的问题了,我跟你谈谈公司的分配方式吧,其实我们公司普通员工的收入都不高的,长沙平均水平,只是不忙,周末休两天,工作满一年还有一个星期的年休假. <br />
　　 <br />
　　但是公司几个部门负责人还是有钱的,象我三十岁,一年18万左右的年薪,其它的我就不清楚了,有几个我一个星期才见一次的,比我还小,只怕拿得比我还多.你应该也是这样的吧. <br />
　　 <br />
　　他要求6千一个月的月薪,我说这倒不重要,重要的是公司不会给你安排业务的,你自己找业务回来,公司给你平台,给你配团队,能挣多少钱是你的本事. <br />
　　 <br />
　　我说完了,问,你有什么想法吗?他说没想法,起身走人. <br />
　　 <br />
　　太有意思了,你在长沙想拿六千一个月,你等别人找事给你做,你为什么不能自己找到项目呀?六千是底薪呀,差不多7万2千的底薪,如果是这样的,那我自己算我应该拿到二十五万以上的年薪了. <br />
　　 <br />
　　从来拿底薪和拿年薪的人就是不一样的. <br />
　　 <br />
　　如果你不敢拿年薪,你就不要想着谈什么老板给你少了. <br />
　　 <br />
　　企业是要盈利的,资本家是要剥削的.问题是,如果你是一个真正能创造价值的人,你自己所创造的价值你是可以拿到手的. <br />
　　 <br />
　　大学毕业生,如果什么经验也没有,只有知识,没有技能,能找到一个给你几百块钱,让你在这里呆着学东西的企业就应该感谢了,如果你觉得这种企业不是你所向往的,你在上大学时就老老实实努力学,少玩,多练. <br />
　　 <br />
　　我工作有一个总结,钱永远不会是目标,但是它会是结果. <br />
<br />
　　谈到职业规划，有人说过职业可以规划的，我也相信未来可以计划的，问题是，你是不是这个能不能计划出你未来的人，以及，你身边有没有熟悉你的高 人 指 点，如果没有，那你自己都不会明白你自己的未来是什么的，就象象你去做所谓的性向测试，说不定是你自己在自欺欺人了，这种事多了，没人会把自己算成一个坏人的。 <br />
<br />
　　所以重要的还是那一句话，复杂的生活简单过，简单的事情重复做。 <br />
　　 <br />
　　你是中文系的，如果你的年纪还不是很大，建议你凭你自己的能力，哪怕是工资少点，你都要进最好的广告公司，去呆上一年半载，按我说的方法偷师，基本能力提升了，慢慢的你会遇到一些贵人的，还有你会涉及一些行业，慢慢的，你会发觉你内心深处喜欢的行业。 <br />
　　 <br />
　　呵呵，特别是哦，女孩子，只有努力才能进大公司，只有进了大公司才能遇到优秀的男生。好男生都关在写字楼里上班下班加班的，呵呵。生活圈子都小的，你选择的工作圈在你努力的阶段就是你的生活圈。 <br />
<br />
　　在你的成长过程中，有五个人非常重要。 <br />
　　　　 <br />
　　第一个，导师，教练。 <br />
　　他教给你实用的技巧、一定的工作经验，而不是知识。他可以给你指明方向。 <br />
　　这个人可能是你的上司、前辈、学长。 <br />
　　　　 <br />
　　第二个，陪练，同路人。 <br />
　　任何人的成长都不是学出来的，而是学而习，习而成习惯，练出来的。在这个练的过程中，是一件很苦的过程，是一系列简单动作的重复重复再重复，由量变到质变的过程，在这个过程中，一个人很难坚持下来，这时你需要一个同路人。 <br />
　　他可以是和你共同兴趣，共同目标的朋友，最好是你生命中所爱的人。 <br />
　　　　 <br />
　　第三个，榜样，他是你人生的标杆。 <br />
　　在你一生中，在不同阶段，会有不同的标杆，你向他学习，受他鼓舞，一步一步向他靠扰。 <br />
　　最重要的是那个你看得到摸得着的人，你知道，不需要通过机遇，只需要通过努力就可以达到的榜样。 <br />
　　　　 <br />
　　第四个，敌人，看不起你的人，拒绝过你的人。 <br />
　　人不到绝境是不会有斗志的，你要证明他是错的，他会给你真正的动力。 <br />
　　　　 <br />
　　第五个，最重要的是第五个，你们觉得第五个人是你自己。 <br />
　　世界上没有救世主，任何希望当别人救世主的人不是疯子就是傻子，只有自己才可以救自己。 <br />
　　这个世界上，失败的人除了天分太差之外，只有以下几点，懒，方向不对，方法不对，没有坚持。 <br />
　　如果你自己做不到，你不要怪别人。 <br />
<br />
　　基本功是你自己的，细节所积累下来的，能让你迅速融入新环境． <br />
　　/* 人和人最终的差距就是在基本功上面，是否迅速。 */ <br />
　　 <br />
　　不知道怎么跟大家谈基本功这个问题． <br />
<br />
　　很多东西大家都没把它当基本功了． <br />
<br />
　　比如说，我想要的人，他打字很快，他很少很少写错别字，有丰富的词汇量，逻辑很清晰，用词很准确，这些看上去难不难？ <br />
　　 <br />
　　但是在我这两年见过的应聘的策划文案来看，只有两个人做到了．一个是做了三年文案的女孩子，慢慢磨的．一个是中文硕士生，还没毕业． <br />
　　 <br />
　　其实大学到底教给大家什么了？ <br />
　　知识？ <br />
　　 <br />
　　大学阶段必须打好你的基本功，这些决定了你就业后的学习能力，阶层简单工作的工作效率． <br />
　　 <br />
　　如果谁还说打字、排版是文员做的事，那只能说他是真正不明白真正的职场需要。 <br />
　　 <br />
　　你们在大学所学到的知识，都是同质化的了，如果将知识变为通用的、标准化的技能才是重要的。 <br />
　　 <br />
　　既然学的东西没用，那在大学还要不要认真学习呢？ <br />
　　 <br />
　　当然要，因为这些东西是系统性的，这个学习过程能培养你的学习能力。 <br />
　　 <br />
　　知识不能改变你的命运了，但是它可以改变你的气质。 <br />
　　 <br />
　　如果你读个四年大学出来，你的气质还不能好一点，那你的大学就真的白读了。 <br />
　　 <br />
　　经常有人在问面试穿什么衣服呀？ <br />
　　 <br />
　　穿什么衣服重要吗？ <br />
　　 <br />
　　重要的是什么人在穿这些衣服。 <br />
　　 <br />
　　重要的是你的精气神，你的气质。 <br />
　　 <br />
　　有一天有一个应聘文案的来了，我叫设计总监先和他聊聊。 <br />
　　 <br />
　　聊完了，我说这个人不行吧，设计总监说为什么？ <br />
　　 <br />
　　我说我们调性不符，我们多少都有点书卷气，而他是一脸的江湖气。 <br />
　　 <br />
　　果然，呵呵。 <br />
　　 <br />
　　招聘方当然是要看应聘者的外形条件的，但并不是丑的就不招，重要的是能力和你的气质，是不是符合公司要求的。 <br />
<br />
　　重要的是兴趣。 <br />
　　 <br />
　　然后是狂练基本功，简单重复积累。 <br />
　　 <br />
　　学打拳，你先站三个月桩再说。 <br />
　　 <br />
　　面对新人，我说很多东西，你会发现，每个字你都认识，每句话你都看得懂，但是你理解吗？ <br />
　　 <br />
　　领悟，是教不了的。 <br />
　　 <br />
　　自己努力吧，自己重复做，再会明白自己最想要的是什么。 <br />
　　 <br />
　　你考公员员如果死活考不上，那你应该去想想，这种机械性的考试你都过不了，那是不是学习方法，或者兴趣不对呀？ <br />
　　 <br />
　　做销售，同样的，从基阶做起吧。 <br />
　　 <br />
　　你的财政学对你有没有帮助？ <br />
　　 <br />
　　当然有，你对销售的认识会不同的。 <br />
　　 <br />
　　象十年前我卖保险，人人都跟银行比，算利息，都算得没有银行高，只能说死了人有赔了。 <br />
　　 <br />
　　而我是怎么算呢？我用递增，还是增减年金公式算，呵呵，比银行高呢。 <br />
　　 <br />
　　另外，别人说死了人有赔，最多是说得婉转点。 <br />
　　 <br />
　　我可没把它当死人卖呀，我把它当礼物卖，当成父母送给孩子的礼物卖，卖得可好了，呵呵。 <br />
　　 <br />
　　现在哪个做人寿险的人敢说他一年做两百多单？ <br />
　　 <br />
　　呵呵，我好象一年做了二百四十单左右，全是年缴哦。 <br />
<br />
　　这个世界上最穷的和最富的人都在做销售． <br />
　　 <br />
　　做销售的人底薪很低的，大多数人拼的只是体力罢了，如果你想做好，你多花心思就可以了．多想多跑，还是在一个行业里多坚持，找到高手做师父带你． <br />
<br />
　　我说说当年我混日子的时候怎么过来的． <br />
　　 <br />
　　那年头电脑还紧俏，我只要一有机会就到别人电脑上练东西，终于练成了今天的电脑基本功，一方面要多学，一方面要多用心． <br />
　　 <br />
　　然后，我每天做记录，记下工作的流程，记下别人说过的工作中重要的话，其实什么叫行业经验，很多老手随便说的话，都是行话了，有它的意思的，听了就要想，就要去查，很多东西就知道了． <br />
　　 <br />
　　为什么要记录，因为什么叫职业化？职业化就是标准化、流程化，模式化，你多看多记多想就能明白了，这些东西在很多地方都是通用的。 <br />
　　/* 职业精神 */ <br />
<br />
　　有一点，如果这里收入还可以的话，你好好学吧，任何工作都要呆一两年，你才会有认识的，跳来跳去的对你不好，真的，你还在磨性情的时候，只要你保持学习的能力，别下班玩去了就可以了，有压力才有动力，好好留心心仪的公司招聘的要求，按那个要求去做一个一年的训练与学习计划，一年后，那个公司在等你。
<img src ="http://www.blogjava.net/xixidabao/aggbug/177926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2008-01-26 16:17 <a href="http://www.blogjava.net/xixidabao/archive/2008/01/26/177926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向对象设计模式与原则</title><link>http://www.blogjava.net/xixidabao/archive/2007/04/29/114505.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sun, 29 Apr 2007 02:26:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/29/114505.html</guid><description><![CDATA[<table cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=title vAlign=center align=middle height=56><strong><font color=#ff0000 size=3>面向对象设计模式与原则<br><!-- #EndEditable --></font></strong></td>
        </tr>
        <tr>
            <td class=formtitle align=middle height=40><!-- #BeginEditable "2" --><!-- #EndEditable --></td>
        </tr>
    </tbody>
</table>
<table height=65 cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=content height=65><!-- #BeginEditable "3" -->
            <table width=760 align=center>
                <tbody>
                    <tr>
                        <td class=content><strong>设计模式简介</strong>
                        <p>每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心。<br>-- Christopher Alexander</p>
                        <p>设计模式描述了软件设计过程中某一类常见问题的一般性的解决方案。面向对象设计模式描述了面向对象设计过程中、特定场景下、类与相互通信的对象之间常见的组织关系。</p>
                        <p><strong>GoF23 种设计模式</strong></p>
                        <p>历史性著作《设计模式：可复用面向对象软件的基础》一书中描述了23种经典面向对象设计模式，创立了模式在软件设计中的地位。该书<br>四位作者被人们并称为Gang of Four （GoF），&#8220;四人组&#8221;，该书描述的23种经典设计模式又被人们称为GoF23 种设计模式。</p>
                        <p>由于《设计模式：可复用面向对象软件的基础》一书确定了设计模式的地位，人们通常所说的设计模式隐含地表示&#8220;面向对象设计模式&#8221;。<br>但这并不意味&#8220;设计模式&#8221;就等于&#8220;面向对象设计模式&#8221;，也不意味着GoF23种模式就表示了所有的&#8220;面向对象设计模式&#8221;。除了&#8220;面向对象设计模式&#8221;外，还有其他设计模式。除了GoF23 种设计模式外，还有更多的面向对象设计模式。</p>
                        <p>GoF23 种设计模式是学习面向对象设计模式的起点，而非终点；本培训课程的目标是让学员在建立在有效方法的基础上，掌握GoF23种设计模式。</p>
                        <p><strong>设计模式与面向对象</strong></p>
                        <p>面向对象设计模式解决的是&#8220;类与相互通信的对象之间的组织关系，包括它们的角色、职责、协作方式几个方面。</p>
                        <p>面向对象设计模式是&#8220;好的面向对象设计&#8221;，所谓&#8220;好的面向对象设计&#8221;是那些可以满足&#8220;应对变化，提高复用&#8221;的设计。</p>
                        <p>面向对象设计模式描述的是软件设计，因此它是独立于编程语言的，但是面向对象设计模式的最终实现仍然要使用面向对象编程语言来表达，本课程基于C#语言，但实际上它适用于支持.NET框架的所有.NET语言，如Visual Basic.NET、C++/CLI等。</p>
                        <p>面向对象设计模式不像算法技巧，可以照搬照用，它是建立在对&#8220;面向对象&#8221;纯熟、深入的理解的基础上的经验性认识。掌握面向对象设计模式的前提是首先掌握&#8220;面向对象&#8221;！ </p>
                        <p><strong>从编程语言直观了解面向对象</strong></p>
                        <p>各种面向对象编程语言相互有别，但都能看到它们对面向对象三大机制的支持，即： &#8220;封装、继承、多态&#8221;</p>
                        <blockquote>&#8211; 封装，隐藏内部实现<br>&#8211; 继承，复用现有代码<br>&#8211; 多态，改写对象行为</blockquote>
                        <p>使用面向对象编程语言（如C#），可以推动程序员以面向对象的思维来思考软件设计结构，从而强化面向对象的编程范式。</p>
                        <p>C#是一门支持面向对象编程的优秀语言，包括：各种级别的封装支持；单实现继承+多接口实现；抽象方法与虚方法重写。</p>
                        <p><strong>但OOPL并非面向对象的全部</strong></p>
                        <p>通过面向对象编程语言（OOPL）认识到的面向对象，并不是面向对象的全部，甚至只是浅陋的面向对象。</p>
                        <p>OOPL的三大机制&#8220;封装、继承、多态&#8221; 可以表达面向对象的所有概念，但这三大机制本身并没有刻画出面向对象的核心精神。换言之，既可以用这三大机制做出&#8220;好的面向对象设计&#8221;，也可以用这三大机制 做出&#8220;差的面向对象设计&#8221;。不是使用了面向对象的语言（例如C#），就实现了面向对象的设计与开发！因此我们不能依赖编程语言的面向对象机制，来掌握面向对象。</p>
                        <p>OOPL没有回答面向对象的根本性问题——我们为什么要使用面向对象？我们应该怎样使用三大机制来实现&#8220;好的面向对象&#8221;？ 我们应该遵循什么样的面向对象原则？</p>
                        <p>任何一个严肃的面向对象程序员（例如C#程序员），都需要系统地学习面向对象的知识，单纯从编程语言上获得的面向对象知识，不能够胜任面向对象设计与开发。</p>
                        <p><strong>从一个示例谈起</strong></p>
                        <p>示例场景：</p>
                        <p>我们需要设计一个人事管理系统，其中的一个功能是对各种不同类型的员工，计算其当月的工资——不同类型的员工，拥有不同的薪金计算制度。</p>
                        <p>结构化做法</p>
                        <p>1.获得人事系统中所有可能的员工类型<br>2.根据不同的员工类型所对应的不同的薪金制度，计算其工资<br>enumEmployeeType<br>{<br>Engineer;<br>Sales;<br>Manager;<br>&#8230;<br>}<br>// 计算工资程序<br>if ( type == EmployeeType.Engineer) <br>{<br>&#8230;&#8230;<br>}<br>else if (type == Employeetype.Sales) <br>{<br>&#8230;&#8230;<br>}</p>
                        <p>面向对象设计</p>
                        <p>1.根据不同的员工类型设计不同的类，并使这些类继承自一个Employee抽象类，其中有一个抽象方法GetSalary。<br>2.在各个不同的员工类中，根据自己的薪金制度，重写（override）GetSalary方法。<br>abstract class Employee<br>{<br>&#8230;<br>public abstract int GetSalary();<br>}<br>class Engineer: Employee<br>{<br>&#8230;<br>public override int GetSalary() <br>{<br>&#8230;<br>}<br>}<br>class Sales: Employee<br>{<br>&#8230;<br>public override int GetSalary() <br>{<br>&#8230;<br>}<br>}<br>// 显示工资程序<br>Employee e = emFactory.GetEmployee(id);<br>MessageBox.Show( e.GetSalary());</p>
                        <p>示例场景：</p>
                        <p>现在需求改变了&#8230;&#8230;随着客户公司业务规模的拓展，又出现了更多类型的员工，比如钟点工、计件工&#8230;&#8230;等等，这对人事管理系统提出了挑战——原有的程序必须改变。</p>
                        <p>结构化做法</p>
                        <p>几乎所有涉及到员工类型的地方（当然包括&#8220;计算工资程序&#8221;）都需要做改变&#8230;&#8230;这些代码都需要重新编译，重新部署&#8230;&#8230;.</p>
                        <p>面向对象做法</p>
                        <p>只需要在新的文件里增添新的员工类，让其继承自Employee抽象类，并重写GetSalary()方法，然后在EmployeeFactory.GetEmployee方法中根据相关条件，产生新的员工类型就可以了。其他地方（显示工资程序、Engineer类、Sales类等）则不需要做任何改变。</p>
                        <p><strong>重新认识面向对象</strong></p>
                        <p>对于前面的例子，从宏观层面来看，面向对象的构建方式更能适应软件的变化，能将变化所带来的影响减为最小</p>
                        <p>从微观层面来看，面向对象的方式更强调各个类的&#8220;责任&#8221;，新增员工类型不会影响原来员工类型的实现代码——这更符合真实的世界，也<br>更能控制变化所影响的范围，毕竟Engineer类不应该为新增的&#8220;钟点工&#8221;来买单&#8230;&#8230;</p>
                        <p>对象是什么？ </p>
                        <blockquote>&#8211; 从概念层面讲，对象是某种拥有责任的抽象。<br>&#8211; 从规格层面讲，对象是一系列可以被其他对象使用的公共接口。<br>&#8211; 从语言实现层面来看，对象封装了代码和数据。</blockquote>
                        <p>有了这些认识之后，怎样才能设计&#8220;好的面向对象&#8221;？</p>
                        <blockquote>&#8211; 遵循一定的面向对象设计原则<br>&#8211; 熟悉一些典型的面向对象设计模式</blockquote>
                        <p><strong>从设计原则到设计模式</strong></p>
                        <p>针对接口编程，而不是针对实现编程</p>
                        <p>&#8211; 客户无需知道所使用对象的特定类型，只需要知道对象拥有客户所期望的接口。</p>
                        <p>优先使用对象组合，而不是类继承</p>
                        <p>&#8211; 类继承通常为&#8220;白箱复用&#8221;，对象组合通常为&#8220;黑箱复用&#8221;。继承在某种程度上破坏了封装性，子类父类耦合度高；而对象组合则只要求被组合的对象具有良好定义的接口，耦合度低。</p>
                        <p>封装变化点</p>
                        <p>&#8211; 使用封装来创建对象之间的分界层，让设计者可以在分界层的一侧进行修改，而不会对另一侧产生不良的影响，从而实现层次间的松耦合。</p>
                        <p>使用重构得到模式——设计模式的应用不宜先入为主，一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。敏捷软件开发实践提倡的&#8220;Refactoring to Patterns &#8221;是目前普遍公认的最好的使用设计模式的方法。</p>
                        <p><strong>几条更具体的设计原则</strong></p>
                        <p>单一职责原则（SRP）：</p>
                        <p>&#8211; 一个类应该仅有一个引起它变化的原因。</p>
                        <p>开放封闭原则（OCP）：</p>
                        <p>&#8211; 类模块应该是可扩展的，但是不可修改（对扩展开放，对更改封闭）</p>
                        <p>Liskov 替换原则（LSP）:<br>&#8211; 子类必须能够替换它们的基类</p>
                        <p>. 依赖倒置原则（DIP）：</p>
                        <p>&#8211; 高层模块不应该依赖于低层模块，二者都应该依赖于抽象。</p>
                        <p>&#8211; 抽象不应该依赖于实现细节，实现细节应该依赖于抽象。</p>
                        <p>接口隔离原则（ISP）：</p>
                        <p>&#8211; 不应该强迫客户程序依赖于它们不用的方法。</p>
                        <p><strong>总结</strong></p>
                        <p>设计模式描述了软件设计过程中某一类常见问题的一般性的解决方 案。面向对象设计模式描述了面向对象设计过程中、特定场景下、类与相互通信的对象之间常见的组织关系。</p>
                        <p>深刻理解面向对象是学好设计模式的基础，掌握一定的面向对象设计原则才能把握面向对象设计模式的精髓，从而实现灵活运用设计模<br>式。</p>
                        <p>三大基本面向对象设计原则</p>
                        <blockquote>&#8211; 针对接口编程，而不是针对实现编程<br>&#8211; 优先使用对象组合，而不是类继承<br>&#8211; 封装变化点</blockquote></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/xixidabao/aggbug/114505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2007-04-29 10:26 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/29/114505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Observer </title><link>http://www.blogjava.net/xixidabao/archive/2007/04/18/111546.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Wed, 18 Apr 2007 03:14:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/18/111546.html</guid><description><![CDATA[<div class=postTitle><a class=postTitle2 id=viewpost1_TitleUrl href="http://www.blogjava.net/Sprite-bei/archive/2007/04/16/110976.html"><u><font color=#800080>设计模式之Observer</font></u></a> </div>
<p><span>Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Observer(观察者)模式是比较常用的一个模式,尤其在界面设计中应用广泛,而本站所关注的是Java在电子商务系统中应用,因此想从电子商务实例中分析Observer的应用.</span></p>
<p>虽然网上商店形式多样<span>,每个站点有自己的特色,但也有其一般的共性,单就"商品的变化,以便及时通知订户"这一点,是很多网上商店共有的模式,这一模式类似Observer patern.</span></p>
<p>具体的说<span>,如果网上商店中商品在名称 价格等方面有变化,如果系统能自动通知会员,将是网上商店区别传统商店的一大特色.这就需要在商品product中加入Observer这样角色,以便product细节发生变化时,Observer能自动观察到这种变化,并能进行及时的update或notify动作.</span></p>
<p><span></span></p>
<p><span>Java的API还为为我们提供现成的Observer接口Java.util.Observer.我们只要直接使用它就可以.</span></p>
<p>我们必须<span>extends Java.util.Observer才能真正使用它:<br>1.提供Add/Delete observer的方法;<br>2.提供通知(notisfy) 所有observer的方法;</span></p>
<table cellSpacing=3 cellPadding=0 width="80%" bgColor=#cccccc border=0>
    <tbody>
        <tr>
            <td>
            <p><span>import java.util.Observable;</span></p>
            <p><span>public class product extends Observable {</span></p>
            <p><span>&nbsp;private String name;</span></p>
            <p><span>&nbsp;private float price;<br>&nbsp;public product(){<br>&nbsp;}</span></p>
            <p><span>&nbsp;public String getName() {<br>&nbsp;&nbsp;return name;<br>&nbsp;}</span></p>
            <p><span>&nbsp;public void setName(String name) {<br>&nbsp;&nbsp;this.name = name;<br>&nbsp;&nbsp;//设置变化点 <br>&nbsp;&nbsp;setChanged();<br>&nbsp;&nbsp;notifyObservers(name);</span></p>
            <p><span>&nbsp;}</span></p>
            <p><span>&nbsp;public float getPrice() {<br>&nbsp;&nbsp;return price;<br>&nbsp;}</span></p>
            <p><span>&nbsp;public void setPrice(float price) {<br>&nbsp;&nbsp;this.price = price;<br>&nbsp;&nbsp;//设置变化点<br>&nbsp;&nbsp;setChanged();<br>&nbsp;&nbsp;notifyObservers(new Float(price));</span></p>
            <p><span>&nbsp;}</span></p>
            <p><span>&nbsp;//以下可以是数据库更新 插入命令.<br>&nbsp;public void saveToDb() {<br>&nbsp;&nbsp;//&nbsp; .....................</span></p>
            <p><span>&nbsp;}</span></p>
            <p><span>&nbsp;public static void main(String[] args) {<br>&nbsp;&nbsp;product p=new product();<br>&nbsp;&nbsp;p.addObserver(new NameObserver());<br>&nbsp;&nbsp;p.addObserver(new PriceObserver());<br>&nbsp;&nbsp;p.setPrice(100);<br>&nbsp; p.setName("name");<br>&nbsp;}<br>}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span><br>我们注意到,在product类中 的setXXX方法中,我们设置了 notify(通知)方法, 当调用setXXX,实际上就触发了notisfyObservers方法,这将通知相应观察者应该采取行动了.</span></p>
<p>下面看看这些观察者的代码<span>,他们究竟采取了什么行动:</span></p>
<table cellSpacing=3 cellPadding=0 width="99%" border=0>
    <tbody>
        <tr>
            <td>
            <p><span>//观察者NameObserver主要用来对产品名称(name)进行观察的<br>public class NameObserver implements Observer{</span></p>
            <p>　　<span>private String name=null;</span></p>
            <p>　　<span>public void update(Observable obj,Object arg){<br><br>　　　　if (arg <a href="http://www-900.ibm.com/developerWorks/java/l-leditor/index.shtml" target=_blank><u><font color=#0000ff>instanceof</font></u></a> String){</span></p>
            <p>　　　　<span> name=(String)arg;<br>　　　　 //产品名称改变值在name中<br>　　　　 System.out.println("NameObserver :name changet to "+name);</span></p>
            <p>　　　　<span>}</span></p>
            <p>　　<span>}</span></p>
            <p><span>}</span></p>
            <p><span>//观察者PriceObserver主要用来对产品价格(price)进行观察的<br>public class PriceObserver implements Observer{</span></p>
            <p>　　<span>private float price=0;</span></p>
            <p>　　<span>public void update(Observable obj,Object arg){<br><br>　　　　if (arg instanceof Float){</span></p>
            <p>　　　　<span> price=((Float)arg).floatValue();<br>　　<br>　　　　 System.out.println("PriceObserver :price changet to "+price);</span></p>
            <p>　　　　<span>}</span></p>
            <p>　　<span>}</span></p>
            <p><span>}<br><br></span></p>
            </td>
        </tr>
    </tbody>
</table>
输出结果如下：<br>PriceObserver :price changet to 100.0<br>NameObserver :name changet to name<br><br>转自：<a href="http://www.blogjava.net/Sprite-bei/archive/2007/04/16/110976.html">http://www.blogjava.net/Sprite-bei/archive/2007/04/16/110976.html</a> 
<img src ="http://www.blogjava.net/xixidabao/aggbug/111546.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2007-04-18 11:14 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/18/111546.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式：用Java动态代理实现AOP </title><link>http://www.blogjava.net/xixidabao/archive/2007/04/08/109208.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sun, 08 Apr 2007 02:55:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/08/109208.html</guid><description><![CDATA[<table width="100%" align=center>
    <tbody>
        <tr>
            <td class=title align=middle>设计模式：用Java动态代理实现AOP </td>
        </tr>
        <tr>
            <td align=middle><a href="http://www.itisedu.com/"><u><font color=#800080>http://www.itisedu.com</font></u></a>&nbsp;&nbsp;&nbsp;2006-12-7 15:08:52&nbsp;&nbsp;&nbsp;<a href="http://www.itisedu.com/"><u><font color=#800080>中科永联</font></u></a> </td>
        </tr>
        <tr>
            <td align=left>[关键字]设计模式 Java 动态 代理 AOP </td>
        </tr>
        <tr>
            <td>目前整个开发社区对<a href="http://www.itisedu.com/phrase/200604231341385.html" target=_new><u><font color=#0000ff>AOP</font></u></a>(Aspect&nbsp;Oriented&nbsp;Programing)推崇备至，也涌现出大量支持AOP的优秀<a href="http://www.itisedu.com/phrase/200604241001145.html" target=_new><u><font color=#0000ff>Framework</font></u></a>,--Spring,&nbsp;<a href="http://www.itisedu.com/phrase/200605111438435.html" target=_new><u><font color=#0000ff>JAC</font></u></a>,&nbsp;<a href="http://www.itisedu.com/phrase/200605111343075.html" target=_new><u><font color=#0000ff>Jboss</font></u></a>&nbsp;AOP&nbsp;等等。AOP似乎一时之间成了潮流。Java初学者不禁要发出感慨，<a href="http://www.itisedu.com/phrase/200604240956125.html" target=_new><u><font color=#0000ff>OOP</font></u></a>还没有学通呢，又来AOP。本文不是要在理论上具体阐述何为AOP,&nbsp;为何要进行AOP&nbsp;.&nbsp;要详细了解学习AOP可以到它老家http://aosd.net去瞧瞧。这里只是意图通过一个简单的例子向初学者展示一下如何来进行AOP. <br><br>　　为了简单起见，例子没有没有使用任何第三方的AOP&nbsp;Framework,&nbsp;而是利用Java语言本身自带的动态代理功能来实现AOP.&nbsp; <br><br>　　让我们先回到AOP本身，AOP主要应用于日志记录，性能统计，安全控制,事务处理等方面。它的主要意图就要将日志记录，性能统计，安全控制等等代码从商业逻辑代码中清楚的划分出来，我们可以把这些行为一个一个单独看作系统所要解决的问题，就是所谓的面向问题的编程(不知将AOP译作面向问题的编程是否欠妥)。通过对这些行为的分离，我们希望可以将它们独立地配置到商业方法中，而要改变这些行为也不需要影响到商业方法代码。&nbsp; <br><br>　　假设系统由一系列的BusinessObject所完成业务逻辑功能，系统要求在每一次业务逻辑处理时要做日志记录。这里我们略去具体的业务逻辑代码。&nbsp; <br><br>public&nbsp;interface&nbsp;BusinessInterface&nbsp;{&nbsp; <br>　public&nbsp;void&nbsp;processBusiness();&nbsp; <br>}&nbsp; <br><br>public&nbsp;<a href="http://www.itisedu.com/phrase/200604231359565.html" target=_new><u><font color=#0000ff>class</font></u></a>&nbsp;BusinessObject&nbsp;implements&nbsp;BusinessInterface&nbsp;{&nbsp; <br>　private&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;Logger.getLogger(this.getClass().getName());&nbsp; <br>　public&nbsp;void&nbsp;processBusiness(){&nbsp; <br>　　try&nbsp;{&nbsp; <br>　　　logger.info("start&nbsp;to&nbsp;processing...");&nbsp; <br>　　　//business&nbsp;logic&nbsp;here.&nbsp; <br>　　　System.out.println(&#8220;here&nbsp;is&nbsp;business&nbsp;logic&#8221;);&nbsp; <br>　　　logger.info("end&nbsp;processing...");&nbsp; <br>　　}&nbsp;catch&nbsp;(Exception&nbsp;e){&nbsp; <br>　　　logger.info("exception&nbsp;happends...");&nbsp; <br>　　　//exception&nbsp;handling&nbsp; <br>　　}&nbsp; <br>　}&nbsp; <br>}&nbsp; <br><br>　　这里处理商业逻辑的代码和日志记录代码混合在一起，这给日后的维护带来一定的困难，并且也会造成大量的代码重复。完全相同的log代码将出现在系统的每一个BusinessObject中。&nbsp; <br><br>按照AOP的思想，我们应该把日志记录代码分离出来。要将这些代码分离就涉及到一个问题，我们必须知道商业逻辑代码何时被调用，这样我们好插入日志记录代码。一般来说要截获一个方法，我们可以采用回调方法或者动态代理。动态代理一般要更加灵活一些，目前多数的AOP&nbsp;Framework也大都采用了动态代理来实现。这里我们也采用动态代理作为例子。&nbsp; <br><br>　　<a href="http://www.itisedu.com/phrase/200604181646475.html" target=_new><u><font color=#0000ff>JDK</font></u></a>1.2以后提供了动态代理的支持，<a href="http://www.itisedu.com/phrase/200604232224305.html" target=_new><u><font color=#0000ff>程序</font></u></a>员通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器，然后通过java.lang.reflect.Proxy得到一个代理<a href="http://www.itisedu.com/phrase/200603090845215.html" target=_new><u><font color=#0000ff>对象</font></u></a>，通过这个代理对象来执行商业方法,在商业方法被调用的同时，执行处理器会被自动调用。&nbsp; <br><br>　　有了JDK的这种支持，我们所要做的仅仅是提供一个日志处理器。&nbsp; <br><br>public&nbsp;class&nbsp;LogHandler&nbsp;implements&nbsp;InvocationHandler&nbsp;{&nbsp; <br><br>　private&nbsp;Logger&nbsp;logger&nbsp;＝&nbsp;Logger.getLogger(this.getClass().getName());&nbsp; <br>　　private&nbsp;<a href="http://www.itisedu.com/phrase/200604231338435.html" target=_new><u><font color=#0000ff>Object</font></u></a>&nbsp;delegate;&nbsp; <br>　　public&nbsp;LogHandler(Object&nbsp;delegate){&nbsp; <br>　　　this.delegate&nbsp;=&nbsp;delegate;&nbsp; <br>　　}&nbsp; <br><br>　public&nbsp;Object&nbsp;invoke(Object&nbsp;proxy,&nbsp;Method&nbsp;method,&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Throwable&nbsp;{&nbsp; <br>　　Object&nbsp;o&nbsp;=&nbsp;null;&nbsp; <br>　　try&nbsp;{&nbsp; <br>　　　logger.info("method&nbsp;stats..."&nbsp;＋&nbsp;method);&nbsp; <br>　　　o&nbsp;=&nbsp;method.invoke(delegate,args);&nbsp; <br>　　　logger.info("method&nbsp;ends..."&nbsp;+&nbsp;method);&nbsp; <br>　　}&nbsp;catch&nbsp;(Exception&nbsp;e){&nbsp; <br>　　　logger.info("Exception&nbsp;happends...");&nbsp; <br>　　　//excetpion&nbsp;handling.&nbsp; <br>　　}&nbsp; <br>　　return&nbsp;o;&nbsp; <br>　}&nbsp; <br>}&nbsp; <br><br>　　现在我们可以把BusinessObject里面的所有日志处理代码全部去掉了。&nbsp; <br><br>public&nbsp;class&nbsp;BusinessObject&nbsp;implements&nbsp;BusinessInterface&nbsp;{&nbsp; <br><br>　private&nbsp;Logger&nbsp;logger&nbsp;=&nbsp;Logger.getLogger(this.getClass().getName());&nbsp; <br>　public&nbsp;void&nbsp;processBusiness(){&nbsp; <br>　　//business&nbsp;processing&nbsp; <br>　　System.out.println(&#8220;here&nbsp;is&nbsp;business&nbsp;logic&#8221;);&nbsp; <br>　}&nbsp; <br>}&nbsp; <br><br>　　<a href="http://www.itisedu.com/phrase/200603082208195.html" target=_new><u><font color=#0000ff>客户端</font></u></a>调用商业方法的代码如下： <br><br>BusinessInterface&nbsp;businessImp&nbsp;=&nbsp;new&nbsp;BusinessObject();&nbsp; <br><br>InvocationHandler&nbsp;handler&nbsp;=&nbsp;new&nbsp;LogHandler(businessImp);&nbsp; <br><br>BusinessInterface&nbsp;proxy&nbsp;=&nbsp;(BusinessInterface)&nbsp;Proxy.newProxyInstance(&nbsp; <br>　businessImp.getClass().getClassLoader(),&nbsp; <br>　businessImp.getClass().getInterfaces(),&nbsp; <br>　handler);&nbsp; <br><br>proxy.processBusiness();&nbsp; <br><br>　　程序输出如下：&nbsp; <br><br>INFO:&nbsp;method&nbsp;stats...&nbsp; <br>here&nbsp;is&nbsp;business&nbsp;logic&nbsp; <br>INFO:&nbsp;method&nbsp;ends...&nbsp; <br><br>　　至此我们的第一次小尝试算是完成了。可以看到，采用AOP之后，日志记录和业务逻辑代码完全分开了，以后要改变日志记录的话只需要修改日志记录处理器就行了，而<a href="http://www.itisedu.com/phrase/200603091835065.html" target=_new><u><font color=#0000ff>业务对象</font></u></a>本身（BusinessObject）无需做任何修改。并且这个日志记录不会造成重复代码了，所有的商业处理对象都可以重用这个日志处理器。&nbsp; <br><br>　　当然在实际应用中，这个例子就显得太粗糙了。由于JDK的动态代理并没有直接支持一次注册多个InvocationHandler，那么我们对业务处理方法既要日志记录又要性能统计时，就需要自己做一些变通了。一般我们可以自己定义一个Handler接口，然后维护一个队列存放所有Handler,&nbsp;当InvocationHandler被触发的时候我们依次调用自己的Handler。所幸的是目前几乎所有的AOP&nbsp;Framework都对这方面提供了很好的支持.这里推荐大家使用Spring。 </td>
        </tr>
        <tr>
            <td align=right>来源：赛迪网论坛 </td>
        </tr>
        <tr>
            <td align=middle>中科永联高级技术培训中心本着技术交流、共享精神，部分信息资料为网上收集，如果本页内容侵犯了您的版权，请立刻通知我们，我们将在1个工作日内作出妥善处理，并向您致以诚挚的歉意。 </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/xixidabao/aggbug/109208.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2007-04-08 10:55 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/08/109208.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>模式与J2EE </title><link>http://www.blogjava.net/xixidabao/archive/2007/04/08/109205.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sun, 08 Apr 2007 02:42:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2007/04/08/109205.html</guid><description><![CDATA[<table width="100%" align=center>
    <tbody>
        <tr>
            <td class=title align=middle>模式与J2EE </td>
        </tr>
        <tr>
            <td align=middle><a href="http://www.itisedu.com/"><u><font color=#0000ff>http://www.itisedu.com</font></u></a>&nbsp;&nbsp;&nbsp;2006-5-12 15:56:28&nbsp;&nbsp;&nbsp;<a href="http://www.itisedu.com/"><u><font color=#0000ff>中科永联</font></u></a> </td>
        </tr>
        <tr>
            <td align=left>[关键字]模式 J2EE </td>
        </tr>
        <tr>
            <td>
            <p>
            <p><font face=Verdana></font></p>
            <font face=Verdana><br>信息工程是以当前数据系统为基础，在一个企业或企业的主要部门，关于建设<a href="http://www.itisedu.com/phrase/200603011147495.html" target=_new><u><font color=#0000ff>信息系统</font></u></a>的规 划、分析、设计和构成的一整套相互关联的正规化、自动化的技术应用。
            <p>&nbsp;</p>
            <p>--- J<a href="http://www.itisedu.com/phrase/200603091620485.html" target=_new><u><font color=#0000ff>AM</font></u></a><a href="http://www.itisedu.com/phrase/200604231411155.html" target=_new><u><font color=#0000ff>ES</font></u></a> Martin&nbsp; </p>
            <p>&nbsp;&nbsp;&nbsp; 正如上面信息工程的创始人James Martin为信息工程的概念所做定义<a href="http://www.itisedu.com/phrase/200603090857555.html" target=_new><u><font color=#0000ff>类</font></u></a>似，<a href="http://www.itisedu.com/phrase/200603061709535.html" target=_new><u><font color=#0000ff>模式</font></u></a>(<a href="http://www.itisedu.com/phrase/200604231320535.html" target=_new><u><font color=#0000ff>pattern</font></u></a>s)的创始人建筑师Chri<a href="http://www.itisedu.com/phrase/200604231411575.html" target=_new><u><font color=#0000ff>ST</font></u></a>opher Alexander在&lt;模式语言，1977、1979&gt;一书中对模式的概念进行了如下描述(附注：书名后面的年份代表在各个不同时期的作品，下面形式同上)：<br>每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心。这样，你就能一次又一次的使用该解决方案而不必做重复劳动。每个模式是由三部分组成的一个规则，这个规则描述特定环境、问题和解决方案之间的关系。简单的说，没有一个模式是独立的实体，每个模式都存在着相互支持，但支持的程度不同：大的模式可以内嵌小的模式，同等层次的模式并列存在，而小的模式被嵌入到大的模式之中。 <br>--- Christopher Alexander&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; 模式的概念在<a href="http://www.itisedu.com/phrase/200604232134205.html" target=_new><u><font color=#0000ff>软件</font></u></a>行业被采用以后，得到的广泛的发展，现在已经存在许多种<a href="http://www.itisedu.com/phrase/200603051002565.html" target=_new><u><font color=#0000ff>类型</font></u></a>的模式应用，其中比较有名的箸作有：<a href="http://www.itisedu.com/phrase/200603061811045.html" target=_new><u><font color=#0000ff>GoF</font></u></a>(Erich <a href="http://www.itisedu.com/phrase/200604230903435.html" target=_new><u><font color=#0000ff>GA</font></u></a>mma、Richard Helm、Ralph Johnson和John Vliss<a href="http://www.itisedu.com/phrase/200604261459505.html" target=_new><u><font color=#0000ff>IDE</font></u></a>s四人，简称：Gang of Four[GoF])的&lt;<a href="http://www.itisedu.com/phrase/200603061631585.html" target=_new><u><font color=#0000ff>设计模式</font></u></a>，1995&gt;，Martin Fowler的&lt;分析模式，1997&gt;，Frank Buschmann等人的&lt;<a href="http://www.itisedu.com/phrase/200603122156385.html" target=_new><u><font color=#0000ff>体系结构</font></u></a>模式，1996、2000&gt;、Jim O.Coplien、Niel Harrison等人的&lt;编程模式，1995、1996、1998、1999&gt;和Deepak Alur等人的&lt;<a href="http://www.itisedu.com/phrase/200603091447335.html" target=_new><u><font color=#0000ff>J2EE</font></u></a>核心模式，2001&gt;等，其中最具影响的是GoF的&lt;设计模式&gt;一书，书中详细讨论了三种类型，共23种模式。好的设计源于工作中经验的积累，当设计使用标准的模板以模式的方式进行交流时，模式就成了交流和重用的强大机制，并且可以改善设计和开发软件的方式。模式可以帮助我们在一个特定的环境里整理并记录已知的可重现的问题及解决方案，并且通过模式来与他人交流这些知识，这些模式可以解决在不同环境中重复出现的问题。模式可以使设计重复使用，重复使用已知的解决方案可以缩短设计和开发应用的周期，有效的使用模式，可以使我们远离重复投资的怪圈。模式的关键在于简单性和可重现性。<br>&nbsp;&nbsp;&nbsp; 举一个模式应用的简单示例。例如，在你的便携式<a href="http://www.itisedu.com/phrase/200604231234155.html" target=_new><u><font color=#0000ff>电脑</font></u></a>上运行一个进程中的<a href="http://www.itisedu.com/phrase/200603090845215.html" target=_new><u><font color=#0000ff>对象</font></u></a>，并且这些对象需要和运行在另一进程中的别的对象通信，也许这一进程并不在你的便携式电脑上，而在别的地方。你又不想让系统中的对象担心如何找寻网上的其他对象或者执行<a href="http://www.itisedu.com/phrase/200604241405415.html" target=_new><u><font color=#0000ff>远程过程调用</font></u></a>。这时，可以使用代理(Proxy模式，详见GoF的&lt;设计模式&gt;一书)模式来解决这个问题，你能做的事就是为这个远程对象在你的本地过程中建立一个代理对象，该代理对象和远程对象具有相同的接口。你的本地对象利用通常处理过程中的<a href="http://www.itisedu.com/phrase/200603090938465.html" target=_new><u><font color=#0000ff>消息</font></u></a>发送来和代理交谈。这时代理对象负责把消息传送给实在对象，而不管实在对象位于何处。<br>&nbsp;&nbsp;&nbsp; 由于下面要讲的Java 2平台的企业版(J2EE)应用模式中很多用到了设计模式与<a href="http://www.itisedu.com/phrase/200603121222205.html" target=_new><u><font color=#0000ff>重构</font></u></a>(<a href="http://www.itisedu.com/phrase/200604232047545.html" target=_new><u><font color=#0000ff>Refactoring</font></u></a>)的概念，所以在此有必要再概要介绍一下重构的概念。重构已经被证明可以阻止软件的腐朽和衰败，关于重构方面的有名箸作当然首推是Martin Fowler所写的&lt;重构，1999&gt;一书了，书中详细介绍了重构的七大类型，共70余种具体的重构手法，同时也指出测试机制在重构中的重要性。书中Martin Fowler对重构的概念进行了详细说明：<br>&nbsp;&nbsp;&nbsp; 重构是对软件内部结构的一种调整，目地是在不改变[软件之可察行为]的前提下，提高其可理解性，降低其修改成本。重构是一种有纪律的、经过训练的、有条不紊的<a href="http://www.itisedu.com/phrase/200604232224305.html" target=_new><u><font color=#0000ff>程序</font></u></a>整理方法，可以将整理过程中不小心引入的错误的机率降到最低，本质上说，重构就是在代码写好之后改进它的设计。重构之前，首先检查自己是否有一套可靠的测试机制，这些测试必须有我检验能力。</p>
            <p><br>--- Martin Fowler&nbsp; </p>
            <p>&nbsp;&nbsp;&nbsp; 建立于Java编程语言和Java技术基础之上的J2EE平台是最适用于企业级分布式环境的应用结构，它被设计为面向多层体系的结构。J2EE包含下面关键技术：Java服务器页面(Java Service Page，JSP)、<a href="http://www.itisedu.com/phrase/200603091005185.html" target=_new><u><font color=#0000ff>Servlet</font></u></a>、<a href="http://www.itisedu.com/phrase/200603091138035.html" target=_new><u><font color=#0000ff>Enterprise JavaBean</font></u></a>s(<a href="http://www.itisedu.com/phrase/200604241156485.html" target=_new><u><font color=#0000ff>EJB</font></u></a>)<a href="http://www.itisedu.com/phrase/200603302222545.html" target=_new><u><font color=#0000ff>组件</font></u></a>、<a href="http://www.itisedu.com/phrase/200604261600355.html" target=_new><u><font color=#0000ff>Java消息服务</font></u></a>(<a href="http://www.itisedu.com/phrase/200604261607125.html" target=_new><u><font color=#0000ff>Java Message Service</font></u></a>，<a href="http://www.itisedu.com/phrase/200604261605045.html" target=_new><u><font color=#0000ff>JMS</font></u></a>)、<a href="http://www.itisedu.com/phrase/200604151904545.html" target=_new><u><font color=#0000ff>JDBC</font></u></a>和Java命名与目录接口(Java Naming and <a href="http://www.itisedu.com/phrase/200604231343545.html" target=_new><u><font color=#0000ff>DI</font></u></a>r<a href="http://www.itisedu.com/phrase/200604222051415.html" target=_new><u><font color=#0000ff>EC</font></u></a>tory Interface，JNDI)。由于J2EE平台是<a href="http://www.itisedu.com/phrase/200604161254415.html" target=_new><u><font color=#0000ff>分层</font></u></a>系统，所以我们将J2EE的层次模型化，这个模型使得我们将职责逻辑地分到不同的层中，共分了五个层次：客户层、表示层、业务层、集成层和资源层。因为客户层和资源层并不是J2EE平台直接关注的问题，所以后面介绍的15个J2EE应用模式全部属于上面五层中的中间三层，其中表示层模式包含与Servlet和JSP技术相关的模式、业务层模式包含与EJB技术有关的模式、集成层模式包含与JMS和J<a href="http://www.itisedu.com/phrase/200604231245475.html" target=_new><u><font color=#0000ff>DB</font></u></a>C有关的模式。具体模式可参看下面表格：</p>
            <p>表一：表示层模式
            <table id=AutoNumber1 style="BORDER-COLLAPSE: collapse" borderColor=#111111 cellSpacing=0 cellPadding=0 width="89%" border=1>
                <tbody>
                    <tr>
                        <td align=middle width="50%"><strong>模式名</strong></td>
                        <td align=middle width="50%"><strong>简单描述</strong></td>
                    </tr>
                    <tr>
                        <td width="50%">截取过滤器(Intercepting Filter) </td>
                        <td width="50%">促进请求的预先处理和后处理</td>
                    </tr>
                    <tr>
                        <td width="50%">前端控制器(Front Controller) </td>
                        <td width="50%">提供请求处理的集中控制器</td>
                    </tr>
                    <tr>
                        <td width="50%"><a href="http://www.itisedu.com/phrase/200603141659315.html" target=_new><u><font color=#0000ff>视图</font></u></a>助手(View Helper) </td>
                        <td width="50%">把与表示层格式化无关的逻辑封装到助手组件</td>
                    </tr>
                    <tr>
                        <td width="50%">复合视图(Comp<a href="http://www.itisedu.com/phrase/200604232131175.html" target=_new><u><font color=#0000ff>OS</font></u></a>ite View) </td>
                        <td width="50%">从原子的子组件创建一个聚集视图</td>
                    </tr>
                    <tr>
                        <td width="50%">工作者服务(Service To Worker) </td>
                        <td width="50%">合并分发者组件、前端控制器和视图助手模式</td>
                    </tr>
                    <tr>
                        <td width="50%">分发者视图(Dispatcher View) </td>
                        <td width="50%">合并分发者组件、前端控制器和视图助手模式，把许多动作推迟到视图处理</td>
                    </tr>
                </tbody>
            </table>
            <br><br>表二：业务层模式<br>
            <table id=AutoNumber2 style="BORDER-COLLAPSE: collapse" borderColor=#111111 cellSpacing=0 cellPadding=0 width="90%" border=1>
                <tbody>
                    <tr>
                        <td align=middle width="50%"><strong>模式名</strong></td>
                        <td align=middle width="50%"><strong>简单描述</strong></td>
                    </tr>
                    <tr>
                        <td width="50%">业务委托(Business Delegate) </td>
                        <td width="50%">把表示层和服务层分隔开，并且提供服务的外观和代理接口</td>
                    </tr>
                    <tr>
                        <td width="50%">值对象(Value <a href="http://www.itisedu.com/phrase/200604231338435.html" target=_new><u><font color=#0000ff>object</font></u></a>) </td>
                        <td width="50%">通过减少网络对话，以加速层之间的数据交换</td>
                    </tr>
                    <tr>
                        <td width="50%">会话外观(Session Facade) </td>
                        <td width="50%">隐藏<a href="http://www.itisedu.com/phrase/200603091835065.html" target=_new><u><font color=#0000ff>业务对象</font></u></a>复性，集中化<a href="http://www.itisedu.com/phrase/200603110944215.html" target=_new><u><font color=#0000ff>工作流</font></u></a>处理</td>
                    </tr>
                    <tr>
                        <td width="50%">复合实体(Composite Entity) </td>
                        <td width="50%">通过把参数相关的对象分组进单个实体bean，表示设计粗粒度实体bean的最好经验</td>
                    </tr>
                    <tr>
                        <td width="50%">值对象组装器(Value Object <a href="http://www.itisedu.com/phrase/200604232104015.html" target=_new><u><font color=#0000ff>AS</font></u></a>sembler) </td>
                        <td width="50%">把来自多个数据源的值对象组装成一个复合值对象</td>
                    </tr>
                    <tr>
                        <td width="50%">值列表处理器(Value List Handler) </td>
                        <td width="50%">管理查询执行、结果缓冲、以及结果处理</td>
                    </tr>
                    <tr>
                        <td width="50%">服务定位器(Service Locator) </td>
                        <td width="50%">封装业务服务查找和创建的复杂性，定位业务服务工厂</td>
                    </tr>
                </tbody>
            </table>
            <br><br>表三：集成层模式<br>
            <table id=AutoNumber3 style="BORDER-COLLAPSE: collapse" borderColor=#111111 cellSpacing=0 cellPadding=0 width="91%" border=1>
                <tbody>
                    <tr>
                        <td align=middle width="50%"><strong>模式名</strong></td>
                        <td align=middle width="50%"><strong>简单描述</strong></td>
                    </tr>
                    <tr>
                        <td width="50%"><a href="http://www.itisedu.com/phrase/200604241352355.html" target=_new><u><font color=#0000ff>数据访问对象</font></u></a>(Data Access Object) </td>
                        <td width="50%">抽象数据源，提供对数据的透明访问</td>
                    </tr>
                    <tr>
                        <td width="50%">服务激发器(Service Activator) </td>
                        <td width="50%">加速EJB组件的异步处理</td>
                    </tr>
                </tbody>
            </table>
            </p>
            <p>&nbsp;&nbsp;&nbsp; 由于J2EE模式众多，篇幅有限，这里只概要介绍其中的一种应用模式 - 集成层的数据访问对象(<a href="http://www.itisedu.com/phrase/200604162200335.html" target=_new><u><font color=#0000ff>DAO</font></u></a>)模式，有兴趣的读者可以参看下面参考文献中的资料。<br>数据访问对象模式</p>
            <p>&nbsp;数据访问对象模式</p>
            <p>1、问题<br>&nbsp;&nbsp;&nbsp; 根据数据源不同，数据访问也不同。根据存储的类型(关系<a href="http://www.itisedu.com/phrase/200602271218062.html" target=_new><u><font color=#0000ff>数据库</font></u></a>、<a href="http://www.itisedu.com/phrase/200603101726185.html" target=_new><u><font color=#0000ff>面向对象</font></u></a>数据库等)和供应商不同，持久性存储(比如数据库)的访问差别也很大。当业务组件(如会话bean)或表示组件(如助手组件)需要访问某数据源时，它们可以使用合适的<a href="http://www.itisedu.com/phrase/200604241228185.html" target=_new><u><font color=#0000ff>API</font></u></a>来获得连接性，以及操作该数据源。但是在这些组件中包含连接性和数据访问代码会引入这些组件及数据源实现之间的紧密耦合。组件中这类代码依赖性使应用程序从某种数据源迁移到其它种类的数据源将变得非常麻烦和困难，当数据源变化时，组件也需要改变，以便于能够处理新类型的数据源。</p>
            <p>2、解决方案<br>&nbsp;&nbsp;&nbsp; 使用数据访问对象(DAO)来抽象和封装所有对数据源的访问。DAO管理着与数据源的连接以便于检索和存储数据，DAO实现了用来操作数据源的访问机制。依赖于DAO的业务组件为其<a href="http://www.itisedu.com/phrase/200603082208195.html" target=_new><u><font color=#0000ff>客户端</font></u></a>使用DAO提供了更简单的接口，DAO完全向客户端隐藏了数据源实现细节。由于当低层数据源实现变化时，DAO向客户端提供的接口不会变化，所以该模式允许DAO调整到不同的存储模式，而不会影响其客户端或业务组件。重要的是，DAO充当组件和数据源之间的适配器。</p>
            <p>3、实现策略<br>&nbsp;&nbsp;&nbsp; 通过调整抽象工厂(Abstract Factory)模式和工厂方法(Factory Method，这二个创建型模式的实现详情可参看GoF的&lt;设计模式&gt;一书)模式，DAO模式可以达到很高的灵活度。 </p>
            <p>当低层存储不会随着实现变化而变化时，可以使用工厂方法模式来实现该策略，以产生应用程序需要的大量DAO，如下面<a href="http://www.itisedu.com/phrase/200603071659325.html" target=_new><u><font color=#0000ff>类图</font></u></a>1所示。 <br>当低层存储随着实现的变化而变化时，策略可以通过使用抽象工厂模式而实现。抽象工厂可以基于工厂方法实现而创建，并可使用工厂方法实现，该策略提供一个DAO的抽象工厂对象，其中该对象可以构造多种类型的具体的DAO工厂，每个工厂支持一种不同类型的持久性存储实现。一旦你获取某特定实现的具体DAO工厂，你可以使用它来生成该实现中所支持和实现的DAO，如下面类图2所示。 </p>
            <p><img src="http://www.itisedu.com/manage/Upload/image/2006512155455670.jpg" border=0><br>&nbsp;</p>
            <p>4、应用<br>&nbsp;&nbsp;&nbsp; 当数据访问代码被直接嵌入到有其他不相关职责的某类中时，就会使修改变的十分困难。这时可以采用分离数据访问代码的解决方案，将数据访问代码抽取到一个新类中，并且把该新类逻辑或者物理地移动到离数据源比较近的位置，这样可以增强模块性和可重用性，如下面图3所示。具体作法可以使用提炼类(Extract <a href="http://www.itisedu.com/phrase/200604231359565.html" target=_new><u><font color=#0000ff>Class</font></u></a>，一种重构手法，细节可参看Martin的&lt;重构&gt;一书)方法创建一个新类，并将原来类中把数据访问代码移动到这个新的数据访问对象(DAO)类，使用这个新的DAO对象从控制器类中访问数据。<br>&nbsp;&nbsp;&nbsp; 示例：持久性逻辑被嵌入到一个使用新DAO对象管理的持久性的某企业新DAO对象中，把持久性代码和该企业新DAO对象代码结合起来会创建脆弱的、紧密耦合的代码。当持久性代码是该企业新DAO对象的一部分时，对该持久性存储的任何改动都要求更改该新DAO对象的持久性代码。这种耦合对企业新DAO对象代码维护会带来负面的影响。下面图4为运用分离数据访问对象方法对其进行重构改进后的结果。</p>
            <p><img src="http://www.itisedu.com/manage/Upload/image/2006512155535250.jpg" border=0></p>
            <p>&nbsp;&nbsp;&nbsp; 在15个J2EE模式中，每个模式都作用于设计模式和构架模式之间的某些方面。每个模式不是孤立存在的，需要其它模式的支持才能更加体现其含义和用处，为了最大限度的用好模式，还需要充分理解模式之间的关系。 </p>
            <p>&nbsp;参考文献 </p>
            <p>系统分析员教程 --- 罗晓沛等箸 <br>设计模式：可复用面向对象软件的元素 --- 李英军等译 <br>重构-改善既有代码的设计 --- 侯捷等译 <br>J2EE核心模式 --- 牛志奇等译 <br><a href="http://www.itisedu.com/phrase/200602271429302.html" target=_new><u><font color=#0000ff>UML</font></u></a>精粹(第二版) --- 徐家福译</p>
            </font></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/xixidabao/aggbug/109205.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2007-04-08 10:42 <a href="http://www.blogjava.net/xixidabao/archive/2007/04/08/109205.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java模式设计之单例模式（一）</title><link>http://www.blogjava.net/xixidabao/archive/2006/06/18/53651.html</link><dc:creator>JAVA之路</dc:creator><author>JAVA之路</author><pubDate>Sun, 18 Jun 2006 14:15:00 GMT</pubDate><guid>http://www.blogjava.net/xixidabao/archive/2006/06/18/53651.html</guid><description><![CDATA[<table height=105 cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=title vAlign=center align=middle height=55>Java模式设计之单例模式（一）<font color=#ff0000 size=3><strong><!-- #EndEditable --></strong></font></td>
        </tr>
        <tr>
            <td class=formtitle align=middle height=50><!-- #BeginEditable "2" --><font color=#000080><span style="FONT-FAMILY: 新細明體; mso-bidi-font-family: SimSun; mso-font-kerning: 0pt; mso-ascii-font-family: Comic Sans MS; mso-hansi-font-family: Comic Sans MS">阎宏 作者授权</span> </font><span lang=EN-US style="COLOR: black; FONT-FAMILY: 'Comic Sans MS'; mso-bidi-font-family: SimSun; mso-font-kerning: 0pt"><o:p></o:p></span><!-- #EndEditable --></td>
        </tr>
    </tbody>
</table>
<table height=65 cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=content height=65><!-- #BeginEditable "3" -->
            <table width="85%" align=center border=0>
                <tbody>
                    <tr>
                        <td class=content>
                        <p class=MsoNormal style="MARGIN: 6pt 0cm 6pt 24pt; mso-para-margin-top: .5gd; mso-para-margin-right: 0cm; mso-para-margin-bottom: .5gd; mso-para-margin-left: 2.0gd; mso-layout-grid-align: none"><span lang=EN-US style="COLOR: black; FONT-FAMILY: 'Comic Sans MS'; mso-bidi-font-family: TimesNewRomanPSMT; mso-font-kerning: 0pt"><span class=f14>　　作为对象的创建模式[GOF95]， 单例模式确保某一个类只有一个实例，而且自行实例化并向整个系统提供这个实例。这个类称为单例类。<br><br>　　注：本文乃阎宏博士的《Java与模式》一书的第十五章。<br><br>　　<strong><font color=#ac000>引言</font></strong><br><br>　　<strong>单例模式的要点</strong><br><br>　　单例单例<br><br>　　显然单例模式的要点有三个；一是某各类只能有一个实例；二是它必须自行创建这个事例；三是它必须自行向整个系统提供这个实例。在下面的对象图中，有一个"单例对象"，而"客户甲"、"客户乙" 和"客户丙"是单例对象的三个客户对象。可以看到，所有的客户对象共享一个单例对象。而且从单例对象到自身的连接线可以看出，单例对象持有对自己的引用。<br><br><img onerror="this.src='http://www.yesky.com/image20010518/60558.jpg';" hspace=3 src="http://www.yesky.com/image20010518/60558.jpg" align=center vspace=1 border=1><br><br>　　<strong>资源管理</strong><br><br>　　一些资源管理器常常设计成单例模式。<br><br>　　在计算机系统中，需要管理的资源包括软件外部资源，譬如每台计算机可以有若干个打印机，但只能有一个Printer Spooler， 以避免两个打印作业同时输出到打印机中。每台计算机可以有若干传真卡，但是只应该有一个软件负责管理传真卡，以避免出现两份传真作业同时传到传真卡中的情况。每台计算机可以有若干通信端口，系统应当集中管理这些通信端口，以避免一个通信端口同时被两个请求同时调用。<br><br>　　需要管理的资源包括软件内部资源，譬如，大多数的软件都有一个（甚至多个）属性（properties）文件存放系统配置。这样的系统应当由一个对象来管理一个属性文件。<br><br>　　需要管理的软件内部资源也包括譬如负责记录网站来访人数的部件，记录软件系统内部事件、出错信息的部件，或是对系统的表现进行检查的部件等。这些部件都必须集中管理，不可政出多头。<br><br>　　这些资源管理器构件必须只有一个实例，这是其一；它们必须自行初始化，这是其二；允许整个系统访问自己这是其三。因此，它们都满足单例模式的条件，是单例模式的应用。<br><br>　　<strong>一个例子：Windows 回收站</strong><br><br>　　Windows 9x 以后的视窗系统中都有一个回收站，下图就显示了Windows 2000 的回收站。<br><br><img onerror="this.src='http://www.yesky.com/image20010518/60560.jpg';" hspace=3 src="http://www.yesky.com/image20010518/60560.jpg" align=center vspace=1 border=1><br><br>　　在整个视窗系统中，回收站只能有一个实例，整个系统都使用这个惟一的实例，而且回收站自行提供自己的实例。因此，回收站是单例模式的应用。<br><br>　　<strong>双重检查成例</strong><br><br>　　在本章最后的附录里研究了双重检查成例。双重检查成例与单例模式并无直接的关系，但是由于很多C 语言设计师在单例模式里面使用双重检查成例，所以这一做法也被很多Java 设计师所模仿。因此，本书在附录里提醒读者，双重检查成例在Java 语言里并不能成立，详情请见本章的附录。<br><br>单例模式的结构<br><br>　　单例模式有以下的特点：<br><br>　　　.. 单例类只可有一个实例。<br><br>　　　.. 单例类必须自己创建自己这惟一的实例。<br><br>　　　.. 单例类必须给所有其他对象提供这一实例。<br><br>　　虽然单例模式中的单例类被限定只能有一个实例，但是单例模式和单例类可以很容易被推广到任意且有限多个实例的情况，这时候称它为多例模式（Multiton Pattern） 和多例类（Multiton Class），请见"专题：多例（Multiton ）模式与多语言支持"一章。单例类的简略类图如下所示。<br><br><br><br>　　由于Java 语言的特点，使得单例模式在Java 语言的实现上有自己的特点。这些特点主要表现在单例类如何将自己实例化上。<br><br>　　饿汉式单例类饿汉式单例类是在Java 语言里实现得最为简便的单例类，下面所示的类图描述了一个饿汉式单例类的典型实现。<br><br><br><br>　　从图中可以看出，此类已经自已将自己实例化。<br><br>　　代码清单1：饿汉式单例类<br><br>public class EagerSingleton&nbsp;<br>{&nbsp;<br>private static final EagerSingleton m_instance =&nbsp;<br>new EagerSingleton();&nbsp;<br>/**&nbsp;<br>* 私有的默认构造子&nbsp;<br>*/&nbsp;<br>private EagerSingleton() { }&nbsp;<br>/**&nbsp;<br>* 静态工厂方法&nbsp;<br>*/&nbsp;<br>public static EagerSingleton getInstance()&nbsp;<br>{<br><br>&#183;224&#183;Java 与模式&nbsp;<br>return m_instance;&nbsp;<br>}<br>}&nbsp;<br><br>　　读者可以看出，在这个类被加载时，静态变量m_instance 会被初始化，此时类的私有构造子会被调用。这时候，单例类的惟一实例就被创建出来了。<br><br>　　Java 语言中单例类的一个最重要的特点是类的构造子是私有的，从而避免外界利用构造子直接创建出任意多的实例。值得指出的是，由于构造子是私有的，因此，此类不能被继承。<br></span></span></p>
                        <p><span class=f14>　　<strong>懒汉式单例类</strong><br><br>　　与饿汉式单例类相同之处是，类的构造子是私有的。与饿汉式单例类不同的是，懒汉式单例类在第一次被引用时将自己实例化。如果加载器是静态的，那么在懒汉式单例类被加载时不会将自己实例化。如下图所示，类图中给出了一个典型的饿汉式单例类实现。<br><br><img onerror="this.src='http://www.yesky.com/image20010518/60565.jpg';" hspace=3 src="http://www.yesky.com/image20010518/60565.jpg" align=center vspace=1 border=1><br><br>　　代码清单2：懒汉式单例类<br><br>package com.javapatterns.singleton.demos;<br>public class LazySingleton<br>{<br>private static LazySingleton<br>m_instance = null;<br>/**<br>* 私有的默认构造子，保证外界无法直接实例化<br>*/<br>private LazySingleton() { }<br>/**<br>* 静态工厂方法，返还此类的惟一实例<br>*/<br>synchronized public static LazySingleton<br>getInstance()<br>{<br>if (m_instance == null)<br>{<br>m_instance = new LazySingleton();<br>}<br>return m_instance;<br>}<br>}
                        <p><br>　　读者可能会注意到，在上面给出懒汉式单例类实现里对静态工厂方法使用了同步化，以处理多线程环境。有些设计师在这里建议使用所谓的"双重检查成例"。必须指出的是，"双重检查成例"不可以在Java 语言中使用。不十分熟悉的读者，可以看看后面给出的小节。<br><br>　　同样，由于构造子是私有的，因此，此类不能被继承。饿汉式单例类在自己被加载时就将自己实例化。即便加载器是静态的，在饿汉式单例类被加载时仍会将自己实例化。单从资源利用效率角度来讲，这个比懒汉式单例类稍差些。<br><br>　　从速度和反应时间角度来讲，则比懒汉式单例类稍好些。然而，懒汉式单例类在实例化时， 必须处理好在多个线程同时首次引用此类时的访问限制问题，特别是当单例类作为资源控制器，在实例化时必然涉及资源初始化，而资源初始化很有可能耗费时间。这意味着出现多线程同时首次引用此类的机率变得较大。<br><br>　　饿汉式单例类可以在Java 语言内实现， 但不易在C++ 内实现，因为静态初始化在C++ 里没有固定的顺序，因而静态的m_instance 变量的初始化与类的加载顺序没有保证，可能会出问题。这就是为什么GoF 在提出单例类的概念时，举的例子是懒汉式的。他们的书影响之大，以致Java 语言中单例类的例子也大多是懒汉式的。实际上，本书认为饿汉式单例类更符合Java 语言本身的特点。<br><br></p>
                        </span><br>
                        <p>&#160;</p>
                        <p>&#160;</p>
                        <p><span class=f14>　　<strong>登记式单例类</strong><br><br>　　登记式单例类是GoF 为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。本书把他们的例子翻译为Java 语言，并将它自己实例化的方式从懒汉式改为饿汉式。只是它的子类实例化的方式只能是懒汉式的， 这是无法改变的。如下图所示是登记式单例类的一个例子，图中的关系线表明，此类已将自己实例化。<br><br><img onerror="this.src='http://www.yesky.com/image20010518/60566.jpg';" hspace=3 src="http://www.yesky.com/image20010518/60566.jpg" align=center vspace=1 border=1><br><br>　　代码清单3：登记式单例类<br><br>import java.util.HashMap;<br>public class RegSingleton<br>{<br>static private HashMap m_registry = new HashMap();<br>static<br>{<br>RegSingleton x = new RegSingleton();<br>m_registry.put( x.getClass().getName() ， x);<br>}<br>/**<br>* 保护的默认构造子<br>*/<br>protected RegSingleton() {}<br>/**<br>* 静态工厂方法，返还此类惟一的实例<br>*/<br>static public RegSingleton getInstance(String name)<br>{<br>if (name == null)<br>{<br>name = "com.javapatterns.singleton.demos.RegSingleton";<br>}<br>if (m_registry.get(name) == null)<br>{<br>try<br>{<br>m_registry.put( name，<br>Class.forName(name).newInstance() ) ;<br>}<br>catch(Exception e)<br>{<br>System.out.println("Error happened.");<br>}<br>}<br>return (RegSingleton) (m_registry.get(name) );<br>}<br>/**<br>* 一个示意性的商业方法<br>*/<br>public String about()<br>{<br>return "Hello， I am RegSingleton.";<br>}<br>}<br>　　它的子类RegSingletonChild 需要父类的帮助才能实例化。下图所示是登记式单例类子类的一个例子。图中的关系表明，此类是由父类将子类实例化的。<br><br><img onerror="this.src='http://www.yesky.com/image20010518/60568.jpg';" hspace=3 src="http://www.yesky.com/image20010518/60568.jpg" align=center vspace=1 border=1><br><br>　　下面是子类的源代码。<br><br>　　代码清单4：登记式单例类的子类<br><br><span class=f14>import java.util.HashMap;<br>public class RegSingletonChild extends RegSingleton<br>{<br>public RegSingletonChild() {}<br>/**<br>* 静态工厂方法<br>*/<br>static public RegSingletonChild getInstance()<br>{<br>return (RegSingletonChild)<br>RegSingleton.getInstance(<br>"com.javapatterns.singleton.demos.RegSingletonChild" );<br>}<br>/**<br>* 一个示意性的商业方法<br>*/<br>public String about()<br>{<br>return "Hello， I am RegSingletonChild.";<br>}<br>}</span>
                        <p><br>　　在GoF 原始的例子中，并没有getInstance() 方法，这样得到子类必须调用的getInstance(String name)方法并传入子类的名字，因此很不方便。本章在登记式单例类子类的例子里，加入了getInstance() 方法，这样做的好处是RegSingletonChild 可以通过这个方法，返还自已的实例。而这样做的缺点是，由于数据类型不同，无法在RegSingleton 提供这样一个方法。由于子类必须允许父类以构造子调用产生实例，因此，它的构造子必须是公开的。这样一来，就等于允许了以这样方式产生实例而不在父类的登记中。这是登记式单例类的一个缺点。<br><br>　　GoF 曾指出，由于父类的实例必须存在才可能有子类的实例，这在有些情况下是一个浪费。这是登记式单例类的另一个缺点。</p>
                        </span>
                        <p>&#160;</p>
                        <p>&#160;</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/xixidabao/aggbug/53651.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xixidabao/" target="_blank">JAVA之路</a> 2006-06-18 22:15 <a href="http://www.blogjava.net/xixidabao/archive/2006/06/18/53651.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>