﻿<?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-呓语的博客-随笔分类-设计模式</title><link>http://www.blogjava.net/xieyunlong/category/5649.html</link><description>不管前面的路有多艰辛多长，只要怀着一颗执着的心。成功就离你不远了!</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 18:34:19 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 18:34:19 GMT</pubDate><ttl>60</ttl><item><title>(创建模式)设计模式之Prototype(原型) </title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22692.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 03:31:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22692.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22692.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22692.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22692.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22692.html</trackback:ping><description><![CDATA[<SPAN class=bt>定义: <BR>用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. <BR><BR>Prototype模式允许一个对象再创建另外一个可定制的对象，根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象，这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。 <BR><BR>如何使用? <BR>因为Java中的提供clone()方法来实现对象的克隆(具体了解clone()按这里),所以Prototype模式实现一下子变得很简单. <BR><BR>以勺子为例： <BR><BR>public abstract class AbstractSpoon implements Cloneable <BR>{ <BR>　　String spoonName; <BR><BR>　　public void setSpoonName(String spoonName) {this.spoonName = spoonName;} <BR>　　public String getSpoonName() {return this.spoonName;} <BR><BR>　　public Object clone() <BR>　　{ <BR>　　　　Object object = null; <BR>　　　　try { <BR>　　　　　　object = super.clone(); <BR>　　　　} catch (CloneNotSupportedException exception) { <BR>　　　　　　System.err.println("AbstractSpoon is not Cloneable"); <BR>　　　　} <BR>　　　　return object; <BR>　　} <BR>} <BR><BR><BR>有两个具体实现(ConcretePrototype): <BR><BR>public class SoupSpoon extends AbstractSpoon <BR>{ <BR>　　public SoupSpoon() <BR>　　{ <BR>　　　　setSpoonName("Soup Spoon"); <BR>　　} <BR>} <BR><BR>public class SaladSpoon extends AbstractSpoon <BR>{ <BR>　　public SaladSpoon() <BR>　　{ <BR>　　　　setSpoonName("Salad Spoon"); <BR>　　} <BR>} <BR><BR><BR>调用Prototype模式很简单: <BR><BR>AbstractSpoon spoon = new SoupSpoon(); <BR>AbstractSpoon spoon = new SaladSpoon(); <BR><BR>当然也可以结合工厂模式来创建AbstractSpoon实例。 <BR><BR>在Java中Prototype模式变成clone()方法的使用，由于Java的纯洁的面向对象特性，使得在Java中使用设计模式变得很自然，两者已经几乎是浑然一体了。这反映在很多模式上，如Interator遍历模式。 </SPAN><BR><BR><img src ="http://www.blogjava.net/xieyunlong/aggbug/22692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 11:31 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(行为模式)设计模式之Template </title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22689.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 03:29:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22689.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22689.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22689.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22689.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22689.html</trackback:ping><description><![CDATA[<P style="WORD-BREAK: break-all; LINE-HEIGHT: 16pt; WORD-WRAP: break-word"><SPAN class=bt>Template定义: <BR>定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中. <BR><BR>其实Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: <BR><BR>public abstract class Benchmark <BR>{ <BR>　　/** <BR>　　* 下面操作是我们希望在子类中完成 <BR>　　*/ <BR>　　public abstract void benchmark(); <BR><BR>　　/** <BR>　　* 重复执行benchmark次数 <BR>　　*/ <BR>　　public final long repeat (int count) { <BR>　　　　if (count &lt;= 0) <BR>　　　　　　return 0; <BR>　　　　else { <BR>　　　　　　long startTime = System.currentTimeMillis(); <BR><BR>　　　　for (int i = 0; i &lt; count; i++) <BR>　　　　　　benchmark(); <BR><BR>　　　　long stopTime = System.currentTimeMillis(); <BR>　　　　return stopTime - startTime; <BR>　　} <BR>} <BR>} <BR><BR><BR>在上例中,我们希望重复执行benchmark()操作,但是对benchmark()的具体内容没有说明,而是延迟到其子类中描述: <BR><BR>public class MethodBenchmark extends Benchmark <BR>{ <BR>　　/** <BR>　　* 真正定义benchmark内容 <BR>　　*/ <BR>　　public void benchmark() { <BR><BR>　　　　for (int i = 0; i &lt; Integer.MAX_VALUE; i++){ <BR>　　　 　　System.out.printtln("i="+i);　 　　 <BR>　　　 } <BR>　　} <BR>} <BR><BR><BR>至此,Template模式已经完成,是不是很简单?看看如何使用: <BR><BR>Benchmark operation = new MethodBenchmark(); <BR>long duration = operation.repeat(Integer.parseInt(args[0].trim())); <BR>System.out.println("The operation took " + duration + " milliseconds"); <BR><BR><BR><BR>也许你以前还疑惑抽象类有什么用,现在你应该彻底明白了吧? 至于这样做的好处,很显然啊,扩展性强,以后Benchmark内容变化,我只要再做一个继承子类就可以,不必修改其他应用代码. </SPAN></P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22689.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 11:29 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22689.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(行为模式)设计模式之Command </title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22691.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 03:29:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22691.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22691.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22691.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22691.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22691.html</trackback:ping><description><![CDATA[<P style="WORD-BREAK: break-all; LINE-HEIGHT: 16pt; WORD-WRAP: break-word"><SPAN class=bt>Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体,规定很多的模式,正是这个灵活性,让人有些confuse. <BR><BR>Command定义 <BR>不少Command模式的代码都是针对图形界面的,它实际就是菜单命令,我们在一个下拉菜单选择一个命令时,然后会执行一些动作. <BR><BR>将这些命令封装成在一个类中,然后用户(调用者)再对这个类进行操作,这就是Command模式,换句话说,本来用户(调用者)是直接调用这些命令的,如菜单上打开文档(调用者),就直接指向打开文档的代码,使用Command模式,就是在这两者之间增加一个中间者,将这种直接关系拗断,同时两者之间都隔离,基本没有关系了. <BR><BR>显然这样做的好处是符合封装的特性,降低耦合度,Command是将对行为进行封装的典型模式,Factory是将创建进行封装的模式, <BR>从Command模式,我也发现设计模式一个"通病":好象喜欢将简单的问题复杂化, 喜欢在不同类中增加第三者,当然这样做有利于代码的健壮性 可维护性 还有复用性. <BR><BR>如何使用? <BR>具体的Command模式代码各式各样,因为如何封装命令,不同系统,有不同的做法.下面事例是将命令封装在一个Collection的List中,任何对象一旦加入List中,实际上装入了一个封闭的黑盒中,对象的特性消失了,只有取出时,才有可能模糊的分辨出: <BR><BR>典型的Command模式需要有一个接口.接口中有一个统一的方法,这就是"将命令/请求封装为对象": <BR><BR>public interface Command { <BR>　　public abstract void execute ( ); <BR>} <BR><BR><BR><BR>具体不同命令/请求代码是实现接口Command,下面有三个具体命令 <BR><BR>public class Engineer implements Command { <BR><BR>　　public void execute( ) { <BR>　　　　//do Engineer's command <BR>　　} <BR>} <BR><BR>public class Programmer implements Command { <BR><BR>　　public void execute( ) { <BR>　　　　//do programmer's command <BR>　　} <BR>} <BR><BR>public class Politician implements Command { <BR><BR>　　public void execute( ) { <BR>　　　　//do Politician's command <BR>　　} <BR>} <BR><BR><BR><BR><BR>按照通常做法,我们就可以直接调用这三个Command,但是使用Command模式,我们要将他们封装起来,扔到黑盒子List里去: <BR><BR>public class producer{ <BR>　　public static List produceRequests() { <BR>　　　　List queue = new ArrayList(); <BR>　　　　queue.add( new DomesticEngineer() ); <BR>　　　　queue.add( new Politician() ); <BR>　　　　queue.add( new Programmer() ); <BR>　　　　return queue; <BR>　　} <BR><BR>} <BR><BR><BR>这三个命令进入List中后,已经失去了其外表特征,以后再取出,也可能无法分辨出谁是Engineer 谁是Programmer了,看下面如何调用Command模式: <BR><BR>public class TestCommand { <BR>　　public static void main(String[] args) { <BR>　　　　 <BR>　　　　List queue = Producer.produceRequests(); <BR>　　　　for (Iterator it = queue.iterator(); it.hasNext(); ) <BR>　　　　　　　　//取出List中东东,其他特征都不能确定,只能保证一个特征是100%正确, <BR>　　　　　　　　// 他们至少是接口Command的"儿子".所以强制转换类型为接口Command <BR><BR>　　　　　　　　((Command)it.next()).execute(); <BR>　　 <BR><BR>　　} <BR>} <BR><BR><BR>由此可见,调用者基本只和接口打交道,不合具体实现交互,这也体现了一个原则,面向接口编程,这样,以后增加第四个具体命令时,就不必修改调用者TestCommand中的代码了. <BR><BR>理解了上面的代码的核心原理,在使用中,就应该各人有自己方法了,特别是在如何分离调用者和具体命令上,有很多实现方法,上面的代码是使用"从List过一遍"的做法.这种做法只是为了演示. <BR><BR>使用Command模式的一个好理由还因为它能实现Undo功能.每个具体命令都可以记住它刚刚执行的动作,并且在需要时恢复. <BR><BR>Command模式在界面设计中应用广泛.Java的Swing中菜单命令都是使用Command模式,由于Java在界面设计的性能上还有欠缺,因此界面设计具体代码我们就不讨论,网络上有很多这样的示例. </SPAN></P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22691.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 11:29 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22691.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(行为模式)设计模式之Visitor </title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22687.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 03:27:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22687.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22687.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22687.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22687.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22687.html</trackback:ping><description><![CDATA[<P style="WORD-BREAK: break-all; LINE-HEIGHT: 16pt; WORD-WRAP: break-word"><SPAN class=bt>Visitor定义 <BR>作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作. <BR><BR>在Java中,Visitor模式实际上是分离了collection结构中的元素和对这些元素进行操作的行为. <BR><BR>为何使用Visitor? <BR>Java的Collection(包括Vector和Hashtable)是我们最经常使用的技术,可是Collection好象是个黑色大染缸,本来有各种鲜明类型特征的对象一旦放入后,再取出时,这些类型就消失了.那么我们势必要用If来判断,如: <BR><BR><BR>Iterator iterator = collection.iterator() <BR>while (iterator.hasNext()) { <BR>　　 Object o = iterator.next(); <BR>　　 if (o instanceof Collection) <BR>　　 　　 messyPrintCollection((Collection)o); <BR>　　 else if (o instanceof String) <BR>　　 　　 System.out.println("'"+o.toString()+"'"); <BR>　　 else if (o instanceof Float) <BR>　　 　　 System.out.println(o.toString()+"f"); <BR>　　 else <BR>　　 　　 System.out.println(o.toString()); <BR>} <BR>在上例中,我们使用了 instanceof来判断 o的类型. <BR><BR>很显然,这样做的缺点代码If else if 很繁琐.我们就可以使用Visitor模式解决它. <BR><BR>如何使用Visitor? <BR>针对上例,我们设计一个接口visitor访问者: <BR><BR>public interface Visitor <BR>{ <BR>　　 public void visitCollection(Collection collection); <BR>　　 public void visitString(String string); <BR>　　 public void visitFloat(Float float); <BR>} <BR><BR><BR>在这个接口中,将我们认为Collection有可能的类的类型放入其中. <BR><BR>有了访问者,我们需要被访问者,被访问者就是我们Collection的每个元素Element,我们要为这些Element定义一个可以接受访问的接口(访问和被访问是互动的,只有访问者,被访问者如果表示不欢迎,访问者就不能访问), <BR><BR>我们定义这个接口叫Visitable,用来定义一个Accept操作,也就是说让Collection每个元素具备可访问性. <BR><BR>public interface Visitable <BR>{ <BR>　　 public void accept(Visitor visitor); <BR>} <BR><BR><BR>好了,有了两个接口,我们就要定义他们的具体实现(Concrete class): <BR><BR>public class ConcreteElement implements Visitable <BR>{ <BR>　　 private String value; <BR>　　 public ConcreteElement(String string) { <BR>　　 　　 value = string; <BR>　　 } <BR>　　 //定义accept的具体内容 这里是很简单的一句调用 <BR>　　 public void accept(Visitor visitor) { <BR>　　 　　 visitor.visitString(this); <BR>　　 } <BR>} <BR><BR><BR>再看看访问者的Concrete实现: <BR><BR>public class ConcreteVisitor implements Visitor <BR>{ <BR>　　 //在本方法中,我们实现了对Collection的元素的成功访问 <BR>　　 public void visitCollection(Collection collection) { <BR>　　 　　 Iterator iterator = collection.iterator() <BR>　　 　　 while (iterator.hasNext()) { <BR>　　 　　 　　 Object o = iterator.next(); <BR>　　 　　 　　 if (o instanceof Visitable) <BR>　　 　　 　　 　　 ((Visitable)o).accept(this); <BR>　　 　　 } <BR><BR>　　 public void visitString(String string) { <BR>　　 　　 System.out.println("'"+string+"'"); <BR>　　 } <BR><BR>　　 public void visitFloat(Float float) { <BR>　　 　　 System.out.println(float.toString()+"f"); <BR>　　 } <BR>} <BR><BR><BR><BR><BR>在上面的visitCollection我们实现了对Collection每个元素访问,只使用了一个判断语句,只要判断其是否可以访问. <BR><BR>至此,我们完成了Visitor模式基本架构. <BR><BR>使用Visitor模式的前提 <BR>对象群结构中(Collection) 中的对象类型很少改变,也就是说访问者的身份类型很少改变,如上面中Visitor中的类型很少改变,如果需要增加新的操作,比如上例中我们在ConcreteElement具体实现外,还需要新的ConcreteElement2 ConcreteElement3. <BR><BR>可见使用Visitor模式是有前提的,在两个接口Visitor和Visitable中,确保Visitor很少变化,变化的是Visitable,这样使用Visitor最方便. <BR><BR>如果Visitor也经常变化, 也就是说,对象群中的对象类型经常改变,一般建议是,不如在这些对象类中逐个定义操作.但是Java的Reflect技术解决了这个问题. </SPAN></P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22687.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 11:27 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22687.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(创建模式)设计模式之Builder </title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22688.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 03:27:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22688.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22688.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22688.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22688.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22688.html</trackback:ping><description><![CDATA[<P style="WORD-BREAK: break-all; LINE-HEIGHT: 16pt; WORD-WRAP: break-word"><SPAN class=bt>Builder模式定义: <BR>将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. <BR><BR>Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们.用户不知道内部的具体构建细节.Builder模式是非常类似抽象工厂模式,细微的区别大概只有在反复使用中才能体会到. <BR><BR>为何使用? <BR>是为了将构建复杂对象的过程和它的部件解耦.注意: 是解耦过程和部件. <BR><BR>因为一个复杂的对象,不但有很多大量组成部分,如汽车,有很多部件:车轮 方向盘 发动机还有各种小零件等等,部件很多,但远不止这些,如何将这些部件装配成一辆汽车,这个装配过程也很复杂(需要很好的组装技术),Builder模式就是为了将部件和组装过程分开. <BR><BR>如何使用? <BR>首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示. <BR><BR>首先,需要一个接口,它定义如何创建复杂对象的各个部件: <BR><BR>public interface Builder { <BR><BR>　　//创建部件A　　比如创建汽车车轮 <BR>　　void buildPartA(); <BR>　　//创建部件B 比如创建汽车方向盘 <BR>　　void buildPartB(); <BR>　　//创建部件C 比如创建汽车发动机 <BR>　　void buildPartC(); <BR><BR>　　//返回最后组装成品结果 (返回最后装配好的汽车) <BR>　　//成品的组装过程不在这里进行,而是转移到下面的Director类中进行. <BR>　　//从而实现了解耦过程和部件 <BR>　　Product getResult(); <BR><BR>} <BR><BR><BR>用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说Director的内容是如何将部件最后组装成成品: <BR><BR>public class Director { <BR><BR>　　private Builder builder; <BR><BR>　　public Director( Builder builder ) { <BR>　　　　this.builder = builder; <BR>　　} <BR>　　// 将部件partA partB partC最后组成复杂对象 <BR>　　//这里是将车轮 方向盘和发动机组装成汽车的过程 <BR>　　public void construct() { <BR>　　　　builder.buildPartA(); <BR>　　　　builder.buildPartB(); <BR>　　　　builder.buildPartC(); <BR><BR>　　} <BR><BR>} <BR><BR><BR>Builder的具体实现ConcreteBuilder: <BR>通过具体完成接口Builder来构建或装配产品的部件; <BR>定义并明确它所要创建的是什么具体东西; <BR>提供一个可以重新获取产品的接口: <BR><BR>public class ConcreteBuilder implements Builder { <BR><BR>　　Part partA, partB, partC; <BR>　　public void buildPartA() { <BR>　　　　//这里是具体如何构建partA的代码 <BR><BR>　　}; <BR>　　public void buildPartB() { <BR>　　　　//这里是具体如何构建partB的代码 <BR>　　}; <BR>　　 public void buildPartC() { <BR>　　　　//这里是具体如何构建partB的代码 <BR>　　}; <BR>　　 public Product getResult() { <BR>　　　　//返回最后组装成品结果 <BR>　　}; <BR><BR>} <BR><BR><BR>复杂对象:产品Product: <BR><BR>public interface Product { } <BR><BR><BR>复杂对象的部件: <BR><BR>public interface Part { } <BR><BR><BR><BR>我们看看如何调用Builder模式: <BR>ConcreteBuilder builder = new ConcreteBuilder(); <BR>Director director = new Director( builder ); <BR><BR>director.construct(); <BR>Product product = builder.getResult(); <BR><BR>Builder模式的应用 <BR>在Java实际使用中,我们经常用到"池"(Pool)的概念,当资源提供者无法提供足够的资源,并且这些资源需要被很多用户反复共享时,就需要使用池. <BR><BR>"池"实际是一段内存,当池中有一些复杂的资源的"断肢"(比如数据库的连接池,也许有时一个连接会中断),如果循环再利用这些"断肢",将提高内存使用效率,提高池的性能.修改Builder模式中Director类使之能诊断"断肢"断在哪个部件上,再修复这个部件. </SPAN></P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22688.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 11:27 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22688.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(创建模式)设计模式之Singleton(单态) </title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22686.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 03:25:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22686.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22686.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22686.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22686.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22686.html</trackback:ping><description><![CDATA[<P style="WORD-BREAK: break-all; LINE-HEIGHT: 16pt; WORD-WRAP: break-word"><SPAN class=bt>定义: <BR>Singleton模式主要作用是保证在Java应用程序中，一个类Class只有一个实例存在。 <BR><BR>在很多操作中，比如建立目录 数据库连接都需要这样的单线程操作。 <BR><BR>还有, singleton能够被状态化; 这样，多个单态类在一起就可以作为一个状态仓库一样向外提供服务，比如，你要论坛中的帖子计数器，每次浏览一次需要计数，单态类能否保持住这个计数，并且能synchronize的安全自动加1，如果你要把这个数字永久保存到数据库，你可以在不修改单态接口的情况下方便的做到。 <BR><BR>另外方面，Singleton也能够被无状态化。提供工具性质的功能， <BR><BR>Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存，因为它限制了实例的个数，有利于Java垃圾回收（garbage collection）。 <BR><BR>我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装入的类实际也属于资源。 <BR><BR>如何使用? <BR>一般Singleton模式通常有几种形式: <BR><BR>public class Singleton { <BR><BR>　　private Singleton(){} <BR><BR>　　//在自己内部定义自己一个实例，是不是很奇怪？ <BR>　　//注意这是private 只供内部调用 <BR><BR>　　private static Singleton instance = new Singleton(); <BR><BR>　　//这里提供了一个供外部访问本class的静态方法，可以直接访问　　 <BR>　　public static Singleton getInstance() { <BR>　　　　return instance; 　　 <BR>　　 } <BR>} <BR><BR><BR><BR><BR>第二种形式: <BR><BR>public class Singleton { <BR><BR>　　private static Singleton instance = null; <BR><BR>　　public static synchronized Singleton getInstance() { <BR><BR>　　//这个方法比上面有所改进，不用每次都进行生成对象，只是第一次　　　 　 <BR>　　//使用时生成实例，提高了效率！ <BR>　　if (instance==null) <BR>　　　　instance＝new Singleton(); <BR>　　return instance; 　　} <BR><BR>} <BR><BR><BR><BR><BR>使用Singleton.getInstance()可以访问单态类。 <BR><BR>上面第二中形式是lazy initialization，也就是说第一次调用时初始Singleton，以后就不用再生成了。 <BR><BR>注意到lazy initialization形式中的synchronized，这个synchronized很重要，如果没有synchronized，那么使用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论，有兴趣者进一步研究。 <BR><BR>一般认为第一种形式要更加安全些。 <BR><BR>使用Singleton注意事项： <BR>有时在某些情况下，使用Singleton并不能达到Singleton的目的，如有多个Singleton对象同时被不同的类装入器装载；在EJB这样的分布式系统中使用也要注意这种情况，因为EJB是跨服务器，跨JVM的。 <BR><BR>我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocator为例稍微分析一下： <BR><BR>在Pet Store中ServiceLocator有两种，一个是EJB目录下；一个是WEB目录下，我们检查这两个ServiceLocator会发现内容差不多，都是提供EJB的查询定位服务，可是为什么要分开呢？仔细研究对这两种ServiceLocator才发现区别：在WEB中的ServiceLocator的采取Singleton模式，ServiceLocator属于资源定位，理所当然应该使用Singleton模式。但是在EJB中，Singleton模式已经失去作用，所以ServiceLocator才分成两种，一种面向WEB服务的，一种是面向EJB服务的。 <BR><BR>Singleton模式看起来简单，使用方法也很方便，但是真正用好，是非常不容易，需要对Java的类 线程 内存等概念有相当的了解。 </SPAN></P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22686.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 11:25 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22686.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>工厂模式简介</title><link>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22684.html</link><dc:creator>呓语的博客</dc:creator><author>呓语的博客</author><pubDate>Tue, 06 Dec 2005 03:21:00 GMT</pubDate><guid>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22684.html</guid><wfw:comment>http://www.blogjava.net/xieyunlong/comments/22684.html</wfw:comment><comments>http://www.blogjava.net/xieyunlong/archive/2005/12/06/22684.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xieyunlong/comments/commentRss/22684.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xieyunlong/services/trackbacks/22684.html</trackback:ping><description><![CDATA[<P><STRONG>定义:提供创建对象的接口.</STRONG> <BR><BR>为何使用? <BR>工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式，工厂模式在Java程序系统可以说是随处可见。 <BR><BR>为什么工厂模式是如此常用？因为工厂模式就相当于创建实例对象的new，我们经常要根据类Class生成实例对象，如A a=new A() 工厂模式也是用来创建实例对象的，所以以后new时就要多个心眼，是否可以考虑实用工厂模式，虽然这样做，可能多做一些工作，但会给你系统带来更大的可扩展性和尽量少的修改量。 <BR><BR>我们以类Sample为例， 如果我们要创建Sample的实例对象: <BR><BR>Sample sample=new Sample(); <BR><BR>可是，实际情况是，通常我们都要在创建sample实例时做点初始化的工作,比如赋值 查询数据库等。 <BR><BR>首先，我们想到的是，可以使用Sample的构造函数，这样生成实例就写成: <BR><BR>Sample sample=new Sample(参数); <BR><BR>但是，如果创建sample实例时所做的初始化工作不是象赋值这样简单的事，可能是很长一段代码，如果也写入构造函数中，那你的代码很难看了（就需要Refactor重整）。 <BR><BR>为什么说代码很难看，初学者可能没有这种感觉，我们分析如下，初始化工作如果是很长一段代码，说明要做的工作很多，将很多工作装入一个方法中，相当于将很多鸡蛋放在一个篮子里，是很危险的，这也是有背于Java面向对象的原则，面向对象的封装(Encapsulation)和分派(Delegation)告诉我们，尽量将长的代码分派“切割”成每段，将每段再“封装”起来(减少段和段之间偶合联系性)，这样，就会将风险分散，以后如果需要修改，只要更改每段，不会再发生牵一动百的事情。 <BR><BR>在本例中，首先，我们需要将创建实例的工作与使用实例的工作分开, 也就是说，让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。 <BR><BR>这时我们就需要Factory工厂模式来生成对象了，不能再用上面简单new Sample(参数)。还有,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.现在Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下: <BR><BR>Sample mysample=new MySample(); <BR>Sample hissample=new HisSample(); <BR><BR>随着项目的深入,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的. <BR><BR>但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了. <BR><BR>工厂方法 <BR>你会建立一个专门生产Sample实例的工厂: <BR><BR>public class Factory{ <BR><BR>　　public static Sample creator(int which){ <BR><BR>　　//getClass 产生Sample 一般可使用动态类装载装入类。 <BR>　　if (which==1) <BR>　　　　return new SampleA(); <BR>　　else if (which==2) <BR>　　　　return new SampleB(); <BR><BR>　　} <BR><BR>} <BR><BR><BR>那么在你的程序中,如果要实例化Sample时.就使用 <BR><BR>Sample sampleA=Factory.creator(1); <BR><BR>这样,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,范错误可能性就越少.好象我们从编程序中也能悟出人生道理?呵呵. <BR><BR>使用工厂方法 要注意几个角色，首先你要定义产品接口，如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类，用来生成产品Sample，如下图，最右边是生产的对象Sample： <BR><BR><BR><BR>进一步稍微复杂一点，就是在工厂类上进行拓展，工厂类也有继承它的实现类concreteFactory了。 <BR><BR>抽象工厂 <BR>工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory). <BR><BR>这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2. <BR><BR>这里假设：Sample有两个concrete类SampleA和SamleB，而Sample2也有两个concrete类Sample2A和SampleB2 <BR><BR>那么，我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现，下面就是将上例中的Factory拓展成抽象工厂: <BR><BR>public abstract class Factory{ <BR><BR>　　public abstract Sample creator(); <BR><BR>　　public abstract Sample2 creator(String name); <BR><BR>} <BR><BR>public class SimpleFactory extends Factory{ <BR><BR>　　public Sample creator(){ <BR>　　　　......... <BR>　　　　return new SampleA <BR>　　} <BR><BR>　　public Sample2 creator(String name){ <BR>　　　　......... <BR>　　　　return new Sample2A <BR>　　} <BR><BR>} <BR><BR>public class BombFactory extends Factory{ <BR><BR>　　public Sample creator(){ <BR>　　　　...... <BR>　　　　return new SampleB <BR>　　} <BR><BR>　　public Sample2 creator(String name){ <BR>　　　　...... <BR>　　　　return new Sample2B <BR>　　} <BR><BR>} <BR><BR><BR><BR><BR>从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问，为什么我不可以使用两个工厂方法来分别生产Sample和Sample2? <BR><BR>抽象工厂还有另外一个关键要点，是因为 SimpleFactory内，生产Sample和生产Sample2的方法之间有一定联系，所以才要将这两个方法捆绑在一个类中，这个工厂类有其本身特征，也许制造过程是统一的，比如：制造工艺比较简单，所以名称叫SimpleFactory。 <BR><BR>在实际应用中，工厂方法用得比较多一些，而且是和动态类装入器组合在一起应用， <BR><BR>举例 <BR><BR>我们以Jive的ForumFactory为例，这个例子在前面的Singleton模式中我们讨论过，现在再讨论其工厂模式: <BR><BR>public abstract class ForumFactory { <BR><BR>　　private static Object initLock = new Object(); <BR>　　private static String className = "com.jivesoftware.forum.database.DbForumFactory"; <BR>　　private static ForumFactory factory = null; <BR><BR>　　public static ForumFactory getInstance(Authorization authorization) { <BR>　　　　//If no valid authorization passed in, return null. <BR>　　　　if (authorization == null) { <BR>　　　　　　return null; <BR>　　　　on 单态模式 <BR>　　　　if (factory == null) { <BR>　　　　　　synchronized(initLock) { <BR>　　　　　　　　if (factory == null) { <BR>　　　　　　　　　　　　...... <BR><BR>　　　　　　　　　　try { <BR>　　　　　　　　　　　　　　//动态转载类 <BR>　　　　　　　　　　　　　　Class c = Class.forName(className); <BR>　　　　　　　　　　　　　　factory = (ForumFactory)c.newInstance(); <BR>　　　　　　　　　　} <BR>　　　　　　　　　　catch (Exception e) { <BR>　　　　　　　　　　　　　　return null; <BR>　　　　　　　　　　} <BR>　　　　　　　　} <BR>　　　　　　} <BR>　　　　} <BR><BR>　　　　//Now, 返回 proxy.用来限制授权对forum的访问 <BR>　　　　return new ForumFactoryProxy(authorization, factory, <BR>　　　　　　　　　　　　　　　　　　　　factory.getPermissions(authorization)); <BR>　　} <BR><BR>　　//真正创建forum的方法由继承forumfactory的子类去完成. <BR>　　public abstract Forum createForum(String name, String des cription) <BR>　　throws UnauthorizedException, ForumAlreadyExistsException; <BR><BR>　　.... <BR><BR>} <BR><BR><BR><BR><BR><BR><BR>因为现在的Jive是通过数据库系统存放论坛帖子等内容数据,如果希望更改为通过文件系统实现,这个工厂方法ForumFactory就提供了提供动态接口: <BR><BR>private static String className = "com.jivesoftware.forum.database.DbForum} <BR>　　　　//以下使用了SingletFactory"; <BR><BR>你可以使用自己开发的创建forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以. <BR><BR>在上面的一段代码中一共用了三种模式,除了工厂模式外,还有Singleton单态模式,以及proxy模式,proxy模式主要用来授权用户对forum的访问,因为访问forum有两种人:一个是注册用户 一个是游客guest,那么那么相应的权限就不一样,而且这个权限是贯穿整个系统的,因此建立一个proxy,类似网关的概念,可以很好的达到这个效果. <BR><BR>看看Java宠物店中的CatalogDAOFactory: <BR><BR>public class CatalogDAOFactory { <BR><BR>　　/** <BR><BR>　　* 本方法制定一个特别的子类来实现DAO模式。 <BR>　　* 具体子类定义是在J2EE的部署描述器中。 <BR>　　*/ <BR><BR>　　public static CatalogDAO getDAO() throws CatalogDAOSysException { <BR><BR>　　　　CatalogDAO catDao = null; <BR><BR>　　　　try { <BR><BR>　　　　　　InitialContext ic = new InitialContext(); <BR>　　　　　　//动态装入CATALOG_DAO_CLASS <BR>　　　　　　//可以定义自己的CATALOG_DAO_CLASS，从而在无需变更太多代码 <BR>　　　　　　//的前提下，完成系统的巨大变更。 <BR><BR>　　　　　　String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS); <BR><BR>　　　　　　catDao = (CatalogDAO) Class.forName(className).newInstance(); <BR><BR>　　　　} catch (NamingException ne) { <BR><BR>　　　　　　throw new CatalogDAOSysException(" <BR>　　　　　　　　CatalogDAOFactory.getDAO: NamingException while <BR>　　　　　　　　　　getting DAO type : \n" + ne.getMessage()); <BR><BR>　　　　} catch (Exception se) { <BR><BR>　　　　　　throw new CatalogDAOSysException(" <BR>　　　　　　　　CatalogDAOFactory.getDAO: Exception while getting <BR>　　　　　　　　　　DAO type : \n" + se.getMessage()); <BR><BR>　　　　} <BR><BR>　　　　return catDao; <BR><BR>　　} <BR><BR>} <BR><BR><BR>CatalogDAOFactory是典型的工厂方法，catDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类，这个实现子类在Java宠物店是用来操作catalog数据库，用户可以根据数据库的类型不同，定制自己的具体实现子类，将自己的子类名给与CATALOG_DAO_CLASS变量就可以。 <BR><BR>由此可见，工厂方法确实为系统结构提供了非常灵活强大的动态扩展机制，只要我们更换一下具体的工厂方法，系统其他地方无需一点变换，就有可能将系统功能进行改头换面的变化。<BR><BR><BR>2.工厂模式的简单用例 <BR></P>
<P>工厂模式是J2EE核心模式中较简单的一种，听说Jive论坛中对数种设计模式有着广泛的应用，工厂模式也包括其中，本人就从该模式起步，希望有一天能对各种设计模式运用自如。<BR><BR>现给出一简单用例，模拟一火腿（Ham）生产工厂，工厂可以生产数种类型的Ham，那么在创建了一个工厂实例后，只需要告诉它请你生产何种Ham，它就会给你生产出来：<BR>package test;</P>
<P>interface Ham { //定义接口，用于辅助实现工厂模式<BR>&nbsp;&nbsp;&nbsp; void show();//由Ham工厂生产出的各种Ham将有show()的能力<BR>}<BR>public class FatoryModule {//工厂类，用于产品多种不同种类的Ham<BR>&nbsp;&nbsp;&nbsp; public Ham getHam(String HamType) throws Exception{//工厂类对象生产Ham的动作<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (HamType.equals("HamA")) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new HamA();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (HamType.equals("HamB")) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new HamB();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (HamType.equals("HamC")) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new HamC();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new Exception();//如果该工厂收到生产某种Ham的指令但暂不支持，则抛出异常<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {//测试代码<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FatoryModule fatorymodule = new FatoryModule();<BR>&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ham myHam = fatorymodule.getHam("HamB");//可以方便地创建各种类型的Ham，而程序结构和代码的修改量达到最小<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myHam.show();<BR>&nbsp;&nbsp;&nbsp; } catch (Exception ex) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();//应进一步处理异常<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>class HamA implements Ham { //工厂中生产的一种产品HamA<BR>&nbsp;&nbsp;&nbsp; public void show() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("You got a HamA.");<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>class HamB implements Ham { //工厂生产的另一种产品HamB<BR>&nbsp;&nbsp;&nbsp; public void show() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("You got a HamB.");<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>class HamC implements Ham { //工厂生产的第三种产品HamC<BR>&nbsp;&nbsp;&nbsp; public void show() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("You got a HamC.");<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过程序的演示我得到了以下结论：</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于应用了工厂模式，我只需要告诉工厂对象给我生产一种什么样的Ham（即getHam()方法中的参数），便可以得到此类Ham，而不用写HamX&nbsp; hamX=new HamX(); 要是有数十种不同的Ham对象需要在程序的不同地方被创建，那么使用工厂模式代码将显得简单而统一，每个需要不同Ham的地方仅是getHam()的参数不同。否则程序一旦需要扩展和维护，数十处的new语句将让人头痛。而如果需要添加新的Ham类型，只需要在工厂类中添加即可。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我还这样理解：如果说每种Ham对象的创建都是一条生产线，那么我们用一个工厂将多个生产线封装起来了，从而用户就好比只与工厂传达室的人打交道，告诉他请你们工厂生产一种什么产品，而不是与每一条生产线打交道－－这样说来当然是有好处的。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 敬请各位发表评论：）</P><img src ="http://www.blogjava.net/xieyunlong/aggbug/22684.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xieyunlong/" target="_blank">呓语的博客</a> 2005-12-06 11:21 <a href="http://www.blogjava.net/xieyunlong/archive/2005/12/06/22684.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>