﻿<?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-hengheng123456789-文章分类-Design Pattern</title><link>http://www.blogjava.net/hengheng123456789/category/20692.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 20 Mar 2007 14:37:49 GMT</lastBuildDate><pubDate>Tue, 20 Mar 2007 14:37:49 GMT</pubDate><ttl>60</ttl><item><title>设计模式之Composite(组合)</title><link>http://www.blogjava.net/hengheng123456789/articles/104911.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Tue, 20 Mar 2007 03:26:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104911.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104911.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104911.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104911.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104911.html</trackback:ping><description><![CDATA[
		<p>
				<b>Composite模式定义</b>:<br />将对象以树形结构组织起来,以达成“部分－整体” 的层次结构，使得客户端对单个对象和组合对象的使用具有一致性.</p>
		<p>Composite比较容易理解，想到Composite就应该想到树形结构图。组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时，Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行。可以用牵一动百来形容。</p>
		<p>所以Composite模式使用到Iterator模式，和Chain of Responsibility模式类似。</p>
		<p>
				<b>Composite好处</b>:<br />1.使客户端调用简单，客户端可以一致的使用组合结构或其中单个对象，用户就不必关系自己处理的是单个对象还是整个组合结构，这就简化了客户端代码。<br />2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。</p>
		<p>
				<b>如何使用Composite?</b>
				<br />首先定义一个接口或抽象类，这是设计模式通用方式了，其他设计模式对接口内部定义限制不多，Composite却有个规定，那就是要在接口内部定义一个用于访问和管理Composite组合体的对象们（或称部件Component）.</p>
		<p>下面的代码是以抽象类定义，一般尽量用接口interface,</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public abstract class Equipment<br />{<br />　　private String name; <br />　　//实价<br />　　public abstract double netPrice();<br />　　//折扣价格<br />　　public abstract double discountPrice();<br />　　//增加部件方法　　<br />　　public boolean add(Equipment equipment) { return false; }<br />　　//删除部件方法<br />　　public boolean remove(Equipment equipment) { return false; }<br />　　//注意这里，这里就提供一种用于访问组合体类的部件方法。<br />　　public Iterator iter() { return null; }<br />　　<br />　　public Equipment(final String name) { this.name=name; }<br />} </td>
						</tr>
				</tbody>
		</table>
		<p>抽象类Equipment就是Component定义，代表着组合体类的对象们,Equipment中定义几个共同的方法。</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public class Disk extends Equipment<br />{<br />　　public Disk(String name) { super(name); }<br />　　//定义Disk实价为1<br />　　public double netPrice() { return 1.; }<br />　　//定义了disk折扣价格是0.5 对折。<br />　　public double discountPrice() { return .5; }<br />}</td>
						</tr>
				</tbody>
		</table>
		<p>Disk是组合体内的一个对象，或称一个部件，这个部件是个单独元素( Primitive)。<br />还有一种可能是，一个部件也是一个组合体，就是说这个部件下面还有'儿子'，这是树形结构中通常的情况，应该比较容易理解。现在我们先要定义这个组合体：</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>abstract class CompositeEquipment extends Equipment<br />{<br />　　private int i=0; <br />　　//定义一个Vector 用来存放'儿子'<br />　　private Lsit equipment=new ArrayList();<br /><br />　　public CompositeEquipment(String name) { super(name); }<br /><br />　　public boolean add(Equipment equipment) { <br />　　　　 this.equipment.add(equipment); <br />　　　　 return true; <br />　　 }<br /><br />　　public double netPrice() <br />　　{<br />　　　　double netPrice=0.;<br />　　　　Iterator iter=equipment.iterator();<br />　　　　for(iter.hasNext())<br />　　　　　　netPrice+=((Equipment)iter.next()).netPrice();<br />　　　　return netPrice;<br />　　}<br /><br />　　public double discountPrice() <br />　　{<br />　　　　double discountPrice=0.;<br />　　　　Iterator iter=equipment.iterator();<br />　　　　for(iter.hasNext())<br />　　　　　　discountPrice+=((Equipment)iter.next()).discountPrice();<br />　　　　return discountPrice;<br />　　}<br />　　<br /></p>
										<p>　　//注意这里，这里就提供用于访问自己组合体内的部件方法。<br />　　//上面dIsk 之所以没有，是因为Disk是个单独(Primitive)的元素.<br />　　public Iterator iter()<br />　　{<br />　　　　return equipment.iterator() ;<br />　　{<br />　　//重载Iterator方法<br />　　 public boolean hasNext() { return i&lt;equipment.size(); }<br />　　//重载Iterator方法<br />　　 public Object next()<br />　　 {<br />　　　　if(hasNext())<br />　　　　　　 return equipment.elementAt(i++);<br />　　　　else <br />　　 　　 　 throw new NoSuchElementException();<br />　　 }<br />　　<br /><br />}</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>上面CompositeEquipment继承了Equipment,同时为自己里面的对象们提供了外部访问的方法,重载了Iterator,Iterator是Java的Collection的一个接口，是Iterator模式的实现.</p>
		<p>我们再看看CompositeEquipment的两个具体类:盘盒Chassis和箱子Cabinet，箱子里面可以放很多东西，如底板，电源盒，硬盘盒等；盘盒里面可以放一些小设备，如硬盘 软驱等。无疑这两个都是属于组合体性质的。</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public class Chassis extends CompositeEquipment<br />{<br />　　 public Chassis(String name) { super(name); }<br />　　 public double netPrice() { return 1.+super.netPrice(); }<br />　　 public double discountPrice() { return .5+super.discountPrice(); }<br />} 
<p>public class Cabinet extends CompositeEquipment<br />{<br />　　 public Cabinet(String name) { super(name); }<br />　　 public double netPrice() { return 1.+super.netPrice(); }<br />　　 public double discountPrice() { return .5+super.discountPrice(); }<br />}</p></td>
						</tr>
				</tbody>
		</table>
		<p>至此我们完成了整个Composite模式的架构。</p>
		<p>我们可以看看客户端调用Composote代码:<br /><br />Cabinet cabinet=new Cabinet("Tower");<br /><br />Chassis chassis=new Chassis("PC Chassis");<br />//将PC Chassis装到Tower中 (将盘盒装到箱子里)<br />cabinet.add(chassis);<br />//将一个10GB的硬盘装到 PC Chassis (将硬盘装到盘盒里)<br />chassis.add(new Disk("10 GB"));<br /><br />//调用 netPrice()方法;<br />System.out.println("netPrice="+cabinet.netPrice());<br />System.out.println("discountPrice="+cabinet.discountPrice());<br /><br /></p>
		<p>上面调用的方法netPrice()或discountPrice()，实际上Composite使用Iterator遍历了整个树形结构,寻找同样包含这个方法的对象并实现调用执行.</p>
		<p>Composite是个很巧妙体现智慧的模式，在实际应用中，如果碰到树形结构，我们就可以尝试是否可以使用这个模式。</p>
		<p>以论坛为例，一个版(forum)中有很多帖子(message),这些帖子有原始贴，有对原始贴的回应贴，是个典型的树形结构，那么当然可以使用Composite模式，那么我们进入Jive中看看，是如何实现的.</p>
		<p>
				<b>Jive解剖</b>
				<br />在Jive中 ForumThread是ForumMessages的容器container(组合体).也就是说，ForumThread类似我们上例中的 CompositeEquipment.它和messages的关系如图：<br />[thread]<br />　　 |- [message]<br />　　 |- [message]<br />　　 　　 |- [message]<br />　　 　　 |- [message]<br />　　 　　 　　 |- [message] </p>
		<p>我们在ForumThread看到如下代码：<br /></p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public interface ForumThread {<br />　　 .... <br />　　 public void addMessage(ForumMessage parentMessage, ForumMessage newMessage)<br />　　 　　 　　 throws UnauthorizedException; 
<p>　　 public void deleteMessage(ForumMessage message)<br />　　 　　 　　 throws UnauthorizedException;</p><p>　　<br />　　 public Iterator messages();<br />　　 　　 .... </p><p>}</p></td>
						</tr>
				</tbody>
		</table>
		<p>类似CompositeEquipment, 提供用于访问自己组合体内的部件方法: 增加 删除 遍历.</p>
		<p>结合我的其他模式中对Jive的分析，我们已经基本大体理解了Jive论坛体系的框架，如果你之前不理解设计模式，而直接去看Jive源代码，你肯定无法看懂。</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104911.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-20 11:26 <a href="http://www.blogjava.net/hengheng123456789/articles/104911.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Decorator(油漆工)</title><link>http://www.blogjava.net/hengheng123456789/articles/104322.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 09:57:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104322.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104322.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104322.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104322.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104322.html</trackback:ping><description><![CDATA[
		<p>装饰模式:Decorator常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这两种实体在Decorator模式中是必须的.</p>
		<p>
		</p>
		<p>
				<b>Decorator定义</b>:<br />动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.<br /></p>
		<p>
				<b>为什么使用Decorator</b>?<br />我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的.</p>
		<p>使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator提供了"即插即用"的方法,在运行期间决定何时增加何种功能.</p>
		<p>
				<b>如何使用</b>?<br />举Adapter中的打桩示例,在Adapter中有两种类:方形桩 圆形桩,Adapter模式展示如何综合使用这两个类,在Decorator模式中,我们是要在打桩时增加一些额外功能,比如,挖坑 在桩上钉木板等,不关心如何使用两个不相关的类.</p>
		<p>我们先建立一个接口:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public interface Work<br />{ <br />　　public void insert();</p>
										<p>}<br /></p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>接口Work有一个具体实现:插入方形桩或圆形桩,这两个区别对Decorator是无所谓.我们以插入方形桩为例:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public class SquarePeg implements Work{<br />　　public void insert(){<br />　　　　System.out.println("方形桩插入");<br />　　} 
<p>}<br /></p></td>
						</tr>
				</tbody>
		</table>
		<p>现在有一个应用:需要在桩打入前,挖坑,在打入后,在桩上钉木板,这些额外的功能是动态,可能随意增加调整修改,比如,可能又需要在打桩之后钉架子(只是比喻).</p>
		<p>那么我们使用Decorator模式,这里方形桩SquarePeg是decoratee(被刷油漆者),我们需要在decoratee上刷些"油漆",这些油漆就是那些额外的功能.</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class Decorator implements Work{</p>
										<p>　　private Work work;<br />　　//额外增加的功能被打包在这个List中<br />　　private ArrayList others = new ArrayList(); </p>
										<p>　　//在构造器中使用组合new方式,引入Work对象;<br />　　public Decorator(Work work)<br />　　{<br />　　　　this.work=work;<br />　　 <br />　　　　others.add("挖坑");</p>
										<p>　　　　others.add("钉木板");<br />　　}</p>
										<p>　　public void insert(){</p>　　　　newMethod();<br />　　} 
<p><br />　　<br />　　//在新方法中,我们在insert之前增加其他方法,这里次序先后是用户灵活指定的 　　 <br />　　public void newMethod()<br />　　{<br />　　　　otherMethod();<br />　　　　work.insert();<br /><br /><br />　　} <br /></p><p>　　public void otherMethod()<br />　　{<br />　　　　ListIterator listIterator = others.listIterator();<br />　　　　while (listIterator.hasNext())<br />　　　　{<br />　　　　　　System.out.println(((String)(listIterator.next())) + " 正在进行");<br />　　　　}<br /><br />　　} <br /></p><p>}<br /></p></td>
						</tr>
				</tbody>
		</table>
		<p>在上例中,我们把挖坑和钉木板都排在了打桩insert前面,这里只是举例说明额外功能次序可以任意安排.</p>
		<p>好了,Decorator模式出来了,我们看如何调用:</p>
		<p>Work squarePeg = new SquarePeg(); <br />Work decorator = new Decorator(squarePeg);<br />decorator.insert(); </p>
		<p>
		</p>
		<p>Decorator模式至此完成.</p>
		<p>如果你细心,会发现,上面调用类似我们读取文件时的调用:</p>
		<p>FileReader fr = new FileReader(filename);<br />BufferedReader br = new BufferedReader(fr);</p>
		<p>实际上Java 的I/O API就是使用<a href="http://www-900.ibm.com/developerWorks/java/l-jdkdp/part3/index.shtml#2" target="_blank">Decorator实现的</a>,I/O变种很多,如果都采取继承方法,将会产生很多子类,显然相当繁琐.</p>
		<p>
				<b>Jive中的Decorator实现</b>
				<br />在论坛系统中,有些特别的字是不能出现在论坛中如"打倒XXX",我们需要过滤这些"反动"的字体.不让他们出现或者高亮度显示.</p>
		<p>在IBM Java专栏中专门<a href="http://www-900.ibm.com/developerWorks/java/l-jivesrc/index.shtml#5" target="_blank">谈Jive的文章</a>中,有谈及Jive中ForumMessageFilter.java使用了Decorator模式,其实,该程序并没有真正使用Decorator,而是提示说:针对特别论坛可以设计额外增加的过滤功能,那么就可以重组ForumMessageFilter作为Decorator模式了.</p>
		<p>所以,我们在分辨是否真正是Decorator模式,以及会真正使用Decorator模式,一定要把握好Decorator模式的定义,以及其中参与的角色(Decoratee 和Decorator).</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 17:57 <a href="http://www.blogjava.net/hengheng123456789/articles/104322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Facade(外观 总管 Manager)</title><link>http://www.blogjava.net/hengheng123456789/articles/104318.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 09:42:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104318.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104318.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104318.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104318.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104318.html</trackback:ping><description><![CDATA[
		<p>
				<i>
						<b>Facade模式的定义</b>
				</i>: 为子系统中的一组接口提供一个一致的界面.</p>
		<p>Facade一个典型应用就是数据库JDBC的应用,如下例对数据库的操作:</p>
		<table cellspacing="3" cellpadding="3" width="95%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class DBCompare {<br /></p>
										<p>　　Connection conn = null;<br />　　PreparedStatement prep = null;<br />　　ResultSet rset = null; <br />　　try {<br />　　 　　Class.forName( "&lt;driver&gt;" ).newInstance();<br />　　　　 conn = DriverManager.getConnection( "&lt;database&gt;" );<br />　　　　<br />　　　　 String sql = "SELECT * FROM &lt;table&gt; WHERE &lt;column name&gt; = ?";<br />　　　　 prep = conn.prepareStatement( sql );<br />　　　　 prep.setString( 1, "&lt;column value&gt;" );<br />　　　　 rset = prep.executeQuery();<br />　　　　 if( rset.next() ) {<br />　　　　　　　　System.out.println( rset.getString( "&lt;column name" ) );<br />　　　　　}<br />　　} catch( SException e ) {<br />　　　　 e.printStackTrace();<br />　　} finally {<br />　　　　 rset.close();<br />　　　　 prep.close();<br />　　　　 conn.close();<br />　　}<br />}<br /></p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>上例是Jsp中最通常的对数据库操作办法. </p>
		<p>在应用中,经常需要对数据库操作,每次都写上述一段代码肯定比较麻烦,需要将其中不变的部分提炼出来,做成一个接口,这就引入了facade外观对象.如果以后我们更换Class.forName中的&lt;driver&gt;也非常方便,比如从Mysql数据库换到Oracle数据库,只要更换facade接口中的driver就可以.</p>
		<p>我们做成了一个<a href="http://www.jdon.com/idea/java/%CA%FD%BE%DD%BF%E2.htm" target="_blank">Facade接口</a>,使用该接口,上例中的程序就可以更改如下:</p>
		<table cellspacing="3" cellpadding="3" width="98%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class DBCompare {<br /><br />　 String sql = "SELECT * FROM &lt;table&gt; WHERE &lt;column name&gt; = ?";　　<br /><br />　　try {<br />　　 　　Mysql msql=new mysql(sql);<br />　　　　 prep.setString( 1, "&lt;column value&gt;" );<br />　　　　 rset = prep.executeQuery();<br />　　　　 if( rset.next() ) {<br />　　　　　　　　System.out.println( rset.getString( "&lt;column name" ) );<br />　　　　　}<br />　　} catch( SException e ) {<br />　　　　 e.printStackTrace();<br />　　} finally {<br />　　　　 mysql.close();<br />　　　　 mysql=null;<br />　　}<br />}</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>可见非常简单,所有程序对数据库访问都是使用改接口,降低系统的复杂性,增加了灵活性.</p>
		<p>如果我们要使用连接池,也只要针对facade接口修改就可以.</p>
		<p> </p>
		<p>
				<img height="232" src="http://www.jdon.com/designpatterns/images/facade.jpg" width="500" />
		</p>
		<p>由上图可以看出, facade实际上是个理顺系统间关系,降低系统间耦合度的一个常用的办法,也许你已经不知不觉在使用,尽管不知道它就是facade.</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104318.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 17:42 <a href="http://www.blogjava.net/hengheng123456789/articles/104318.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Adapter(适配器)</title><link>http://www.blogjava.net/hengheng123456789/articles/104295.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 08:36:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104295.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104295.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104295.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104295.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104295.html</trackback:ping><description><![CDATA[
		<p>
				<b>适配器模式定义:</b>
				<br />将两个不兼容的类纠合在一起使用，属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份.</p>
		<p>
				<b>为何使用?</b>
				<br />我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是：修改各自类的接口，但是如果我们没有源代码，或者，我们不愿意为了一个应用而修改各自的接口。 怎么办? </p>
		<p>使用Adapter，在这两种接口之间创建一个混合接口(混血儿).</p>
		<p>
				<b>如何使用?</b>
				<br />实现Adapter方式,其实"think in Java"的"类再生"一节中已经提到,有两种方式：组合(composition)和继承(inheritance).</p>
		<p>
				<br />假设我们要打桩，有两种类：方形桩 圆形桩.<br />public class SquarePeg{<br />　　public void insert(String str){<br />　　　　System.out.println("SquarePeg insert():"+str);<br />　　}</p>
		<p>}</p>
		<p>public class RoundPeg{<br />　　public void insertIntohole(String msg){<br />　　　　System.out.println("RoundPeg insertIntoHole():"+msg);<br />}<br />}</p>
		<p>现在有一个应用,需要既打方形桩,又打圆形桩.那么我们需要将这两个没有关系的类综合应用.假设RoundPeg我们没有源代码,或源代码我们不想修改,那么我们使用Adapter来实现这个应用:</p>
		<p>public class PegAdapter extends SquarePeg{<br /><br />　　private RoundPeg roundPeg;</p>
		<p>　　public PegAdapter(RoundPeg peg)(this.roundPeg=peg;)</p>
		<p>　　public void insert(String str){ roundPeg.insertIntoHole(str);}</p>
		<p>}</p>
		<p>在上面代码中,RoundPeg属于Adaptee,是被适配者.PegAdapter是Adapter,将Adaptee(被适配者RoundPeg)和Target(目标SquarePeg)进行适配.实际上这是将组合方法(composition)和继承(inheritance)方法综合运用.</p>
		<p>PegAdapter首先继承SquarePeg，然后使用new的组合生成对象方式，生成RoundPeg的对象roundPeg，再重载父类insert()方法。从这里,你也了解使用new生成对象和使用extends继承生成对象的不同,前者无需对原来的类修改,甚至无需要知道其内部结构和源代码.</p>
		<p>如果你有些Java使用的经验，已经发现，这种模式经常使用。</p>
		<p>
				<b>进一步使用</b>
				<br />上面的PegAdapter是继承了SquarePeg,如果我们需要两边继承，即继承SquarePeg 又继承RoundPeg,因为Java中不允许多继承，但是我们可以实现(implements)两个接口(interface)</p>
		<p>public interface IRoundPeg{<br />　　public void insertIntoHole(String msg);<br /><br />}</p>
		<p>public interface ISquarePeg{<br />　　public void insert(String str);</p>
		<p>}</p>
		<p>下面是新的RoundPeg 和SquarePeg, 除了实现接口这一区别，和上面的没什么区别。<br />public class SquarePeg implements ISquarePeg{<br />　　public void insert(String str){<br />　　　　System.out.println("SquarePeg insert():"+str);<br />　　}</p>
		<p>}</p>
		<p>public class RoundPeg implements IRoundPeg{<br />　　public void insertIntohole(String msg){<br />　　　　System.out.println("RoundPeg insertIntoHole():"+msg);<br />　　}<br />}</p>
		<p>下面是新的PegAdapter,叫做two-way adapter:</p>
		<p>public class PegAdapter implements IRoundPeg,ISquarePeg{<br /><br />　　private RoundPeg roundPeg;<br />　　private SquarePeg squarePeg;<br /><br />　　// 构造方法<br />　　public PegAdapter(RoundPeg peg){this.roundPeg=peg;}<br />　　// 构造方法<br />　　public PegAdapter(SquarePeg peg)(this.squarePeg=peg;)</p>
		<p>　　public void insert(String str){ roundPeg.insertIntoHole(str);}</p>
		<p>}</p>
		<p>还有一种叫Pluggable Adapters,可以动态的获取几个adapters中一个。使用Reflection技术，可以动态的发现类中的Public方法。</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104295.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 16:36 <a href="http://www.blogjava.net/hengheng123456789/articles/104295.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Proxy(代理)</title><link>http://www.blogjava.net/hengheng123456789/articles/104281.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 07:48:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104281.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104281.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104281.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104281.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104281.html</trackback:ping><description><![CDATA[
		<p>理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣.</p>
		<p>代理模式是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,Proxy是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理.</p>
		<p>
				<b>设计模式中定义</b>: 为其他对象提供一种代理以控制对这个对象的访问.</p>
		<p>
				<b>为什么要使用Proxy?</b>
				<br />1.授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限.</p>
		<p>2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.<br />举例两个具体情况: <br />(1)如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片.<br /><br />(2)如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象.<br /></p>
		<p>总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存. 所以,有些人认为Java耗费资源内存,我以为这和程序编制思路也有一定的关系.</p>
		<p>
				<b>如何使用Proxy?</b>
				<br />以<a href="http://www.jdon.com/dl/jive.zip">Jive论坛系统</a>为例,访问论坛系统的用户有多种类型:注册普通用户 论坛管理者 系统管理者 游客,注册普通用户才能发言;论坛管理者可以管理他被授权的论坛;系统管理者可以管理所有事务等,这些权限划分和管理是使用Proxy完成的.</p>
		<p>Forum是Jive的核心接口,在Forum中陈列了有关论坛操作的主要行为,如论坛名称 论坛描述的获取和修改,帖子发表删除编辑等.</p>
		<p>在ForumPermissions中定义了各种级别权限的用户:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public class ForumPermissions implements Cacheable { 
<p>/**<br />* Permission to read object.<br />*/<br />public static final int READ = 0;</p><p>/**<br />* Permission to administer the entire sytem.<br />*/<br />public static final int SYSTEM_ADMIN = 1;</p><p>/**<br />* Permission to administer a particular forum.<br />*/<br />public static final int FORUM_ADMIN = 2;</p><p>/**<br />* Permission to administer a particular user.<br />*/<br />public static final int USER_ADMIN = 3;</p><p>/**<br />* Permission to administer a particular group.<br />*/<br />public static final int GROUP_ADMIN = 4;</p><p>/**<br />* Permission to moderate threads.<br />*/<br />public static final int MODERATE_THREADS = 5;</p><p>/**<br />* Permission to create a new thread.<br />*/<br />public static final int CREATE_THREAD = 6;</p><p>/**<br />* Permission to create a new message.<br />*/<br />public static final int CREATE_MESSAGE = 7;</p><p>/**<br />* Permission to moderate messages.<br />*/<br />public static final int MODERATE_MESSAGES = 8;</p><p>.....</p><p>public boolean isSystemOrForumAdmin() {<br />　　return (values[FORUM_ADMIN] || values[SYSTEM_ADMIN]);<br />}</p><p>.....</p><p>}</p></td>
						</tr>
				</tbody>
		</table>
		<p>因此,Forum中各种操作权限是和ForumPermissions定义的用户级别有关系的,作为接口Forum的实现:ForumProxy正是将这种对应关系联系起来.比如,修改Forum的名称,只有论坛管理者或系统管理者可以修改,代码如下:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class ForumProxy implements Forum {</p>
										<p>private ForumPermissions permissions;<br />private Forum forum; <br />this.authorization = authorization; <br /><br />public ForumProxy(Forum forum, Authorization authorization,<br />ForumPermissions permissions)<br />{<br />this.forum = forum;<br />this.authorization = authorization;<br />this.permissions = permissions;<br />}<br /><br />.....</p>
										<p>public void setName(String name) throws UnauthorizedException,<br />ForumAlreadyExistsException<br />{<br />　　//只有是系统或论坛管理者才可以修改名称<br />　　if (permissions.isSystemOrForumAdmin()) {<br />　　　　forum.setName(name);<br />　　}<br />　　else {<br />　　　　throw new UnauthorizedException();<br />　　}<br />}</p>
										<p>...</p>
										<p>}<br /></p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>而DbForum才是接口Forum的真正实现,以修改论坛名称为例:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class DbForum implements Forum, Cacheable {<br />...</p>
										<p>public void setName(String name) throws ForumAlreadyExistsException {<br /><br />　　....<br /><br />　　this.name = name;<br />　　//这里真正将新名称保存到数据库中 <br />　　saveToDb();</p>
										<p>　　....<br />}<br /></p>
										<p>
												<br />... </p>
										<p>}</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>凡是涉及到对论坛名称修改这一事件,其他程序都首先得和ForumProxy打交道,由ForumProxy决定是否有权限做某一样事情,ForumProxy是个名副其实的"网关","安全代理系统".</p>
		<p>在平时应用中,无可避免总要涉及到系统的授权或安全体系,不管你有无意识的使用Proxy,实际你已经在使用Proxy了.</p>
		<p>我们继续结合Jive谈入深一点,下面要涉及到工厂模式了,如果你不了解工厂模式,请看我的另外一篇文章:<a href="http://www.jdon.com/designpatterns/designpattern_factory.htm" target="_blank">设计模式之Factory</a></p>
		<p>我们已经知道,使用Forum需要通过ForumProxy,Jive中创建一个Forum是使用Factory模式,有一个总的抽象类ForumFactory,在这个抽象类中,调用ForumFactory是通过getInstance()方法实现,这里使用了Singleton(也是设计模式之一,由于介绍文章很多,我就不写了,<a href="http://www-900.ibm.com/developerWorks/java/designpattern/singleton/index.shtml" target="_blank">看这里</a>),getInstance()返回的是ForumFactoryProxy.</p>
		<p>为什么不返回ForumFactory,而返回ForumFactory的实现ForumFactoryProxy?<br />原因是明显的,需要通过代理确定是否有权限创建forum.</p>
		<p>在ForumFactoryProxy中我们看到代码如下:</p>
		<table cellspacing="3" cellpadding="3" width="98%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public class ForumFactoryProxy extends ForumFactory { 
<p>　　protected ForumFactory factory;<br />　　protected Authorization authorization;<br />　　protected ForumPermissions permissions;</p><p>　　public ForumFactoryProxy(Authorization authorization, ForumFactory factory,<br />　　ForumPermissions permissions)<br />　　{<br />　　　　this.factory = factory;<br />　　　　this.authorization = authorization;<br />　　　　this.permissions = permissions;<br />　　}</p><p>　　public Forum createForum(String name, String description)<br />　　　　　　throws UnauthorizedException, ForumAlreadyExistsException<br />　　{<br />　　　　//只有系统管理者才可以创建forum <br />　　　　if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {<br />　　　　　　Forum newForum = factory.createForum(name, description);<br />　　　　　　return new ForumProxy(newForum, authorization, permissions);<br />　　　　}<br />　　　　else {<br />　　　　　　throw new UnauthorizedException();<br />　　}<br />}<br /></p></td>
						</tr>
				</tbody>
		</table>
		<p>方法createForum返回的也是ForumProxy, Proxy就象一道墙,其他程序只能和Proxy交互操作.</p>
		<p>注意到这里有两个Proxy:ForumProxy和ForumFactoryProxy. 代表两个不同的职责:使用Forum和创建Forum;<br />至于为什么将使用对象和创建对象分开,这也是为什么使用Factory模式的原因所在:是为了"封装" "分派";换句话说,尽可能功能单一化,方便维护修改.</p>
		<p>Jive论坛系统中其他如帖子的创建和使用,都是按照Forum这个思路而来的.</p>
		<p>以上我们讨论了如何使用Proxy进行授权机制的访问,Proxy还可以对用户隐藏另外一种称为copy-on-write的优化方式.拷贝一个庞大而复杂的对象是一个开销很大的操作,如果拷贝过程中,没有对原来的对象有所修改,那么这样的拷贝开销就没有必要.用代理延迟这一拷贝过程.</p>
		<p>比如:我们有一个很大的Collection,具体如hashtable,有很多客户端会并发同时访问它.其中一个特别的客户端要进行连续的数据获取,此时要求其他客户端不能再向hashtable中增加或删除 东东.</p>
		<p>最直接的解决方案是:使用<font color="#ff1493">collection的lock</font>,让这特别的客户端获得这个lock,进行连续的数据获取,然后再释放lock.<br />public void foFetches(Hashtable ht){<br />　　<font color="#ff1493">synchronized(ht)</font>{<br />　　　　//具体的连续数据获取动作.. <br />　　} </p>
		<p>}<br /></p>
		<p>但是这一办法可能锁住Collection会很长时间,这段时间,其他客户端就不能访问该Collection了.</p>
		<p>第二个解决方案是clone这个Collection,然后让连续的数据获取针对clone出来的那个Collection操作.这个方案前提是,这个Collection是可clone的,而且必须有提供深度clone的方法.Hashtable就提供了对自己的clone方法,但不是Key和value对象的clone,关于Clone含义可以参考<a href="http://www-900.ibm.com/developerWorks/java/l-jpointer/index.shtml" target="_blank">专门文章</a>.<br />public void foFetches(Hashtable ht){<br /></p>
		<p>　　Hashttable newht=(Hashtable)ht.clone();</p>
		<p>}</p>
		<p>问题又来了,由于是针对clone出来的对象操作,如果原来的母体被其他客户端操作修改了, 那么对clone出来的对象操作就没有意义了.</p>
		<p>最后解决方案:我们可以等其他客户端修改完成后再进行clone,也就是说,这个特别的客户端先通过调用一个叫clone的方法来进行一系列数据获取操作.但实际上没有真正的进行对象拷贝,直至有其他客户端修改了这个对象Collection.</p>
		<p>使用Proxy实现这个方案.这就是copy-on-write操作.</p>
		<p>Proxy应用范围很广,现在流行的分布计算方式RMI和Corba等都是Proxy模式的应用.</p>
		<p>更多Proxy应用,见<a href="http://www.research.umbc.edu/%7Etarr/cs491/lectures/Proxy.pdf" target="_blank">http://www.research.umbc.edu/~tarr/cs491/lectures/Proxy.pdf</a></p>
		<p>Sun公司的 <a href="http://developer.java.sun.com/developer/technicalArticles/DataTypes/proxy/" target="_blank">Explore the Dynamic Proxy API</a><a href="http://java.sun.com/j2se/1.4/docs/guide/reflection/proxy.html" target="_blank">Dynamic Proxy Classes</a></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 15:48 <a href="http://www.blogjava.net/hengheng123456789/articles/104281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Factory</title><link>http://www.blogjava.net/hengheng123456789/articles/104269.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 07:28:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104269.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104269.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104269.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104269.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104269.html</trackback:ping><description><![CDATA[
		<p>
				<b>
						<i>工厂模式定义<span lang="EN-US">:提供创建对象的接口.</span></i>
				</b>
		</p>
		<p>
				<b>
						<i>为何使用<span lang="EN-US">?</span></i>
				</b>
				<span lang="EN-US">
						<br />工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式，工厂模式在Java程序系统可以说是随处可见。</span>
		</p>
		<p>为什么工厂模式是如此常用？因为工厂模式就相当于创建实例对象的<span lang="EN-US">new，我们经常要根据类Class生成实例对象，如A a=new A() 工厂模式也是用来创建实例对象的，所以以后new时就要多个心眼，是否可以考虑实用工厂模式，虽然这样做，可能多做一些工作，但会给你系统带来更大的可扩展性和尽量少的修改量。</span></p>
		<p>我们以类<span lang="EN-US">Sample为例， 如果我们要创建Sample的实例对象:</span></p>
		<p>
				<span lang="EN-US">Sample sample=new Sample();</span>
		</p>
		<p>可是，实际情况是，通常我们都要在创建<span lang="EN-US">sample实例时做点初始化的工作,比如赋值 查询数据库等。</span></p>
		<p>首先，我们想到的是，可以使用<span lang="EN-US">Sample的构造函数，这样生成实例就写成:</span></p>
		<p>
				<span lang="EN-US">Sample sample=new Sample(参数);</span>
		</p>
		<p>但是，如果创建<span lang="EN-US">sample实例时所做的初始化工作不是象赋值这样简单的事，可能是很长一段代码，如果也写入构造函数中，那你的代码很难看了（就需要Refactor重整）。</span></p>
		<p>为什么说代码很难看，初学者可能没有这种感觉，我们分析如下，初始化工作如果是很长一段代码，说明要做的工作很多，将很多工作装入一个方法中，相当于将很多鸡蛋放在一个篮子里，是很危险的，这也是有背于<span lang="EN-US">Java面向对象的原则，面向对象的封装(Encapsulation)和分派(Delegation)告诉我们，尽量将长的代码分派“切割”成每段，将每段再“封装”起来(减少段和段之间偶合联系性)，这样，就会将风险分散，以后如果需要修改，只要更改每段，不会再发生牵一动百的事情。</span></p>
		<p>在本例中，首先，我们需要将<font color="#ff1493">创建实例的工作</font>与<font color="#ff1493">使用实例的工作</font>分开<span lang="EN-US">, 也就是说，让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。</span></p>
		<p>这时我们就需要<span lang="EN-US">Factory工厂模式来生成对象了，不能再用上面简单new Sample(参数)。</span>还有<span lang="EN-US">,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.</span>现在<span lang="EN-US">Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下:</span></p>
		<p>
				<span lang="EN-US">Sample mysample=new MySample();<br />Sample hissample=new HisSample();</span>
		</p>
		<p>随着项目的深入<span lang="EN-US">,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.</span></p>
		<p>但如果你一开始就有意识使用了工厂模式<span lang="EN-US">,这些麻烦就没有了.</span></p>
		<p>
				<strong>工厂方法<br /></strong>你会建立一个专门生产<span lang="EN-US">Sample实例的工厂:</span></p>
		<table style="WIDTH: 80%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="80%" border="0">
				<tbody>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: #cccccc; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt">
										<p>
												<span lang="EN-US">public class Factory{</span>
										</p>
										<p>　　<span lang="EN-US">public static Sample creator(int which){</span></p>
										<p>　　//getClass <span lang="EN-US">产生Sample 一般可使用动态类装载装入类。<br />　　if (which==1)<br />　　　　return new SampleA();<br />　　else if (which==2)<br />　　　　return new SampleB();</span></p>
										<p>　　<span lang="EN-US">}</span></p>
										<p>
												<span lang="EN-US">}</span>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>那么在你的程序中<span lang="EN-US">,如果要实例化Sample时.就使用</span></p>
		<p>
				<span lang="EN-US">Sample sampleA=Factory.creator(1);</span>
		</p>
		<p>这样<span lang="EN-US">,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,范错误可能性就越少.好象我们从编程序中也能悟出人生道理?呵呵.</span></p>
		<p>使用工厂方法 要注意几个角色，首先你要定义产品接口，如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类，用来生成产品Sample，如下图，最右边是生产的对象Sample：</p>
		<p>
				<img height="178" src="http://www.jdon.com/designpatterns/images/factory.jpg" width="526" />
		</p>
		<p>进一步稍微复杂一点，就是在工厂类上进行拓展，工厂类也有继承它的实现类concreteFactory了<b><i>。</i></b></p>
		<p>
				<span lang="EN-US">
						<strong>抽象工厂</strong>
						<br />工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).</span>
		</p>
		<p style="MARGIN-BOTTOM: 12pt">
				<span lang="EN-US">这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2.</span>
		</p>
		<p style="MARGIN-BOTTOM: 12pt">这里假设：Sample有两个concrete类SampleA和SamleB，而Sample2也有两个concrete类Sample2A和SampleB2</p>
		<p style="MARGIN-BOTTOM: 12pt">
				<span lang="EN-US">那么，我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现，下面就是将上例中的Factory拓展成抽象工厂:</span>
		</p>
		<table style="WIDTH: 80%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: #cccccc; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt">
										<p>
												<span lang="EN-US">public abstract class Factory{</span>
										</p>
										<p>　　<span lang="EN-US">public abstract Sample creator();</span></p>
										<p>　　<span lang="EN-US">public abstract Sample2 creator(String name); </span></p>
										<p>
												<span lang="EN-US">}</span>
										</p>
										<p>
												<span lang="EN-US">public class SimpleFactory extends Factory{</span>
										</p>
										<p>　　<span lang="EN-US">public Sample creator(){<br />　　　　.........<br />　　<span lang="EN-US"></span>　　<span lang="EN-US"></span>return new SampleA</span><span lang="EN-US"><br />　　}</span></p>
										<p>　　<span lang="EN-US">public Sample2 creator(String name){<br />　　　　.........<br />　　<span lang="EN-US"></span>　　<span lang="EN-US"></span>return new Sample2A</span><span lang="EN-US"></span><span lang="EN-US"><br />　　}</span></p>
										<p>
												<span lang="EN-US">}</span>
										</p>
										<p>
												<span lang="EN-US">public class BombFactory extends Factory{</span>
										</p>
										<p>　　<span lang="EN-US">public Sample creator(){<br />　　　　......<br />　　<span lang="EN-US"></span>　　<span lang="EN-US"></span>return new SampleB</span><span lang="EN-US"></span><span lang="EN-US"><br />　　}</span></p>
										<p>　　<span lang="EN-US">public Sample2 creator(String name){<br />　　　　......<br />　　<span lang="EN-US"></span>　　<span lang="EN-US"></span>return new Sample2B<br />　　}</span></p>
										<p>
												<span lang="EN-US">}</span>
										</p>
										<p>
												<span lang="EN-US">
												</span> </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<span lang="EN-US">从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问，为什么我不可以使用两个工厂方法来分别生产Sample和Sample2? </span>
		</p>
		<p>
				<span lang="EN-US">抽象工厂还有另外一个关键要点，是因为 SimpleFactory内，生产Sample和生产Sample2的方法之间有一定联系，所以才要将这两个方法捆绑在一个类中，这个工厂类有其本身特征，也许制造过程是统一的，比如：制造工艺比较简单，所以名称叫SimpleFactory。</span>
				<span lang="EN-US">
						<br />
				</span>
		</p>
		<p>在实际应用中，工厂方法用得比较多一些，而且是和动态类装入器组合在一起应用，</p>
		<p>
				<span lang="EN-US">
						<strong>举例</strong>
						<?XML:NAMESPACE PREFIX = O /?>
						<o:p>
						</o:p>
				</span>
		</p>
		<p>我们以<span lang="EN-US">Jive的ForumFactory为例，这个例子在前面的Singleton模式中我们讨论过，现在再讨论其工厂模式:</span></p>
		<table style="WIDTH: 97%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="97%" border="0">
				<tbody>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: #cccccc; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt">
										<p>
												<span lang="EN-US">public abstract class ForumFactory {</span>
										</p>
										<p>　　<span lang="EN-US">private static Object initLock = new Object();<br />　　private static String className = "com.jivesoftware.forum.database.DbForumFactory";<br />　　private static ForumFactory factory = null; </span></p>
										<p>　　<span lang="EN-US">public static ForumFactory getInstance(Authorization authorization) {<br />　　　　//If no valid authorization passed in, return null.<br />　　　　if (authorization == null) {<br />　　　　　　return null;<br />　　　　}<br />　　　　//以下使用了Singleton 单态模式<br />　　　　if (factory == null) {<br />　　　　　　synchronized(initLock) {<br />　　　　　　　　if (factory == null) {<br />　　　　　　　　　　　　...... </span></p>
										<p>　　　　　　　　　　<span lang="EN-US">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 />　　　　}</span></p>
										<p>　　　　<span lang="EN-US">//Now, 返回 proxy.用来限制授权对forum的访问<br />　　　　return new ForumFactoryProxy(authorization, factory,<br />　　　　　　　　　　　　　　　　　　　　factory.getPermissions(authorization));<br />　　}</span></p>
										<p>　　<span lang="EN-US">//真正创建forum的方法由继承forumfactory的子类去完成.<br />　　public abstract Forum createForum(String name, String description)<br />　　throws UnauthorizedException, ForumAlreadyExistsException;</span></p>
										<p>　　<span lang="EN-US">....</span></p>
										<p>
												<span lang="EN-US">}</span>
										</p>
										<p>
												<span lang="EN-US">
												</span> </p>
										<p>
												<span lang="EN-US">
												</span> </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>因为现在的<span lang="EN-US">Jive是通过数据库系统存放论坛帖子等内容数据,如果希望更改为通过文件系统实现,这个工厂方法ForumFactory就提供了提供动态接口:</span></p>
		<p>
				<span lang="EN-US">private static String className = "com.jivesoftware.forum.database.DbForumFactory";</span>
		</p>
		<p>你可以使用自己开发的创建<span lang="EN-US">forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以.</span></p>
		<p>在上面的一段代码中一共用了三种模式<span lang="EN-US">,除了工厂模式外,还有Singleton单态模式,以及proxy模式,proxy模式主要用来授权用户对forum的访问,因为访问forum有两种人:一个是注册用户 一个是游客guest,那么那么相应的权限就不一样,而且这个权限是贯穿整个系统的,因此建立一个proxy,类似网关的概念,可以很好的达到这个效果.  </span></p>
		<p>看看<span lang="EN-US">Java宠物店中的CatalogDAOFactory:</span></p>
		<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#cccccc" border="0">
				<tbody>
						<tr>
								<td>public class CatalogDAOFactory { 
<p></p><p>　　/**</p><p>　　* 本方法制定一个特别的子类来实现DAO模式。<br />　　* 具体子类定义是在J2EE的部署描述器中。<br />　　*/</p><p>　　public static CatalogDAO getDAO() throws CatalogDAOSysException {</p><p>　　　　CatalogDAO catDao = null;</p><p>　　　　try {</p><p>　　　　　　InitialContext ic = new InitialContext();<br />　　　　　　//动态装入CATALOG_DAO_CLASS<br />　　　　　　//可以定义自己的CATALOG_DAO_CLASS，从而在无需变更太多代码<br />　　　　　　//的前提下，完成系统的巨大变更。</p><p>　　　　　　String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS);</p><p>　　　　　　catDao = (CatalogDAO) Class.forName(className).newInstance();</p><p>　　　　} catch (NamingException ne) {</p><p>　　　　　　throw new CatalogDAOSysException("<br />　　　　　　　　CatalogDAOFactory.getDAO: NamingException while <br />　　　　　　　　　　getting DAO type : \n" + ne.getMessage());</p><p>　　　　} catch (Exception se) {</p><p>　　　　　　throw new CatalogDAOSysException("<br />　　　　　　　　CatalogDAOFactory.getDAO: Exception while getting <br />　　　　　　　　　　DAO type : \n" + se.getMessage());</p><p>　　　　}</p><p>　　　　return catDao;</p><p>　　}</p><p>}<br /></p></td>
						</tr>
				</tbody>
		</table>
		<p>
				<br style="mso-ignore: vglayout" clear="all" />
		</p>
		<p>
				<span lang="EN-US">CatalogDAOFactory是典型的工厂方法，catDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类，这个实现子类在Java宠物店是用来操作catalog数据库，用户可以根据数据库的类型不同，定制自己的具体实现子类，将自己的子类名给与CATALOG_DAO_CLASS变量就可以。</span>
		</p>
		<p>由此可见，工厂方法确实为系统结构提供了非常灵活强大的动态扩展机制，只要我们更换一下具体的工厂方法，系统其他地方无需一点变换，就有可能将系统功能进行改头换面的变化。</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104269.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 15:28 <a href="http://www.blogjava.net/hengheng123456789/articles/104269.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Singleton(单态)</title><link>http://www.blogjava.net/hengheng123456789/articles/104253.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 06:59:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104253.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104253.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104253.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104253.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104253.html</trackback:ping><description><![CDATA[
		<p>
				<strong>单态定义</strong>:<br />Singleton模式主要作用是保证在Java应用程序中，一个类Class只有一个实例存在。 </p>
		<p>在很多操作中，比如建立目录 数据库连接都需要这样的单线程操作。</p>
		<p>还有, singleton能够被状态化; 这样，多个单态类在一起就可以作为一个状态仓库一样向外提供服务，比如，你要论坛中的帖子计数器，每次浏览一次需要计数，单态类能否保持住这个计数，并且能synchronize的安全自动加1，如果你要把这个数字永久保存到数据库，你可以在不修改单态接口的情况下方便的做到。</p>
		<p>另外方面，Singleton也能够被无状态化。提供工具性质的功能，<br /><br />Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存，因为它限制了实例的个数，有利于Java垃圾回收（garbage collection）。<br /><br />我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装入的类实际也属于资源。<br /></p>
		<p>
				<strong>如何使用?</strong>
				<br />一般Singleton模式通常有几种形式:</p>
		<table cellspacing="3" cellpadding="3" width="100%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class Singleton {</p>
										<p>　　private Singleton(){}</p>
										<p>　　//在自己内部定义自己一个实例，是不是很奇怪？<br />　　//注意这是private 只供内部调用</p>
										<p>　　private static Singleton instance = new Singleton();</p>
										<p>　　//这里提供了一个供外部访问本class的静态方法，可以直接访问　　<br />　　public static Singleton getInstance() {<br />　　　　return instance; 　　<br />　　 } <br />} </p>
										<p> </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>第二种形式:</p>
		<table cellspacing="3" cellpadding="3" width="100%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public class Singleton { 
<p>　　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; 　　} </p><p>} </p><p> </p></td>
						</tr>
				</tbody>
		</table>
		<p>使用Singleton.getInstance()可以访问单态类。</p>
		<p>上面第二中形式是lazy initialization，也就是说第一次调用时初始Singleton，以后就不用再生成了。</p>
		<p>注意到lazy initialization形式中的synchronized，这个<font color="#ff1493">synchronized很重要</font>，如果没有synchronized，那么使用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论，有兴趣者进一步研究。</p>
		<p>
				<font style="BACKGROUND-COLOR: #0000ff">
						<font style="BACKGROUND-COLOR: #7fffd4">一般认为第一种形式要更加安全些。</font>
						<br />
				</font>
		</p>
		<p>
				<strong>使用Singleton注意事项</strong>：<br /><br />有时在某些情况下，使用Singleton并不能达到Singleton的目的，如有多个Singleton对象同时被不同的类装入器装载；在EJB这样的分布式系统中使用也要注意这种情况，因为EJB是跨服务器，跨JVM的。</p>
		<p>我们以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服务的。</p>
		<p>Singleton模式看起来简单，使用方法也很方便，但是真正用好，是非常不容易，需要对Java的类 线程 内存等概念有相当的了解。</p>
		<p>总之：<font color="#0000ff">如果你的应用基于容器，那么Singleton模式少用或者不用，可以使用相关替代技术。</font></p>
		<p>
		</p>
		<p>进一步深入可参考：</p>
		<p>
				<a href="http://www-106.ibm.com/developerworks/java/library/j-dcl.html?dwzone=java" target="_blank">Double-checked locking and the Singleton pattern</a>
		</p>
		<p>
				<a href="http://www.javaworld.com/javaworld/jw-01-2001/jw-0112-singleton-p3.html#resources" target="_blank">When is a singleton not a singleton?</a>
		</p>
		<p>
				<a href="http://www.jdon.com/jive/thread.jsp?forum=91&amp;thread=17578" target="_blank">Singleton是邪恶的</a>
		</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104253.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 14:59 <a href="http://www.blogjava.net/hengheng123456789/articles/104253.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Builder</title><link>http://www.blogjava.net/hengheng123456789/articles/104240.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 05:52:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104240.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104240.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104240.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104240.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104240.html</trackback:ping><description><![CDATA[
		<p>
				<b>Builder模式定义</b>:<br />将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.</p>
		<p>Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们.用户不知道内部的具体构建细节.Builder模式是非常类似抽象工厂模式,细微的区别大概只有在反复使用中才能体会到.</p>
		<p>
				<b>为何使用?</b>
				<br />是为了将构建复杂对象的<b><i>过程</i></b>和它的<i><b>部件</b></i>解耦.注意: 是解耦<b><i>过程</i></b>和<i><b>部件</b></i>.</p>
		<p>因为一个复杂的对象,不但有很多大量组成部分,如汽车,有很多部件:车轮 方向盘 发动机还有各种小零件等等,部件很多,但远不止这些,如何将这些部件装配成一辆汽车,这个装配过程也很复杂(需要很好的组装技术),Builder模式就是为了将部件和组装过程分开.<br /></p>
		<p>
				<b>如何使用?</b>
				<br />首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示.<br /></p>
		<p>首先,需要一个接口,它定义如何创建复杂对象的各个部件:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public interface Builder { </p>
										<p>　　//创建部件A　　比如创建汽车车轮<br />　　void buildPartA(); <br />　　//创建部件B 比如创建汽车方向盘<br />　　void buildPartB(); <br />　　//创建部件C 比如创建汽车发动机<br />　　void buildPartC(); <br /><br />　　//返回最后组装成品结果 (返回最后装配好的汽车)<br />　　//成品的组装过程不在这里进行,而是转移到下面的Director类中进行.<br />　　//从而实现了解耦<b><i>过程</i></b>和<i><b>部件</b></i><br />　　Product getResult(); </p>
										<p>} </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说Director的内容是如何将部件最后组装成成品:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class Director {</p>
										<p>　　private Builder builder; </p>
										<p>　　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(); </p>
										<p>　　} </p>
										<p>} </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>Builder的具体实现ConcreteBuilder:<br />通过具体完成接口Builder来构建或装配产品的部件;<br />定义并明确它所要创建的是什么具体东西;<br />提供一个可以重新获取产品的接口:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class ConcreteBuilder implements Builder { </p>
										<p>　　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 /></p>
										<p>}</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>复杂对象:产品Product:<br /></p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public interface Product { } </td>
						</tr>
				</tbody>
		</table>
		<p>复杂对象的部件:</p>
		<table cellspacing="3" cellpadding="3" width="80%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public interface Part { }</td>
						</tr>
				</tbody>
		</table>
		<p>
				<br />我们看看如何调用Builder模式:<br />ConcreteBuilder builder = new ConcreteBuilder();<br />Director director = new Director( builder ); <br /><br />director.construct();    //<font color="#0000ff">部件的创建</font><br />Product product = builder.getResult();  //<font color="#0000ff">对象（产品）的创建</font></p>
		<p>
				<b>Builder模式的应用<br /></b>在Java实际使用中,我们经常用到"池"(Pool)的概念,当资源提供者无法提供足够的资源,并且这些资源需要被很多用户反复共享时,就需要使用池.</p>
		<p>"池"实际是一段内存,当池中有一些复杂的资源的"断肢"(比如数据库的连接池,也许有时一个连接会中断),如果循环再利用这些"断肢",将提高内存使用效率,提高池的性能.修改Builder模式中Director类使之能诊断"断肢"断在哪个部件上,再修复这个部件.</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104240.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 13:52 <a href="http://www.blogjava.net/hengheng123456789/articles/104240.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Prototype(原型)</title><link>http://www.blogjava.net/hengheng123456789/articles/104222.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Fri, 16 Mar 2007 05:18:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/articles/104222.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/104222.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/articles/104222.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/104222.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/104222.html</trackback:ping><description><![CDATA[
		<p>原型模式定义:<br />用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.</p>
		<p>Prototype模式允许一个对象再创建另外一个可定制的对象，根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象，这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。</p>
		<p>如何使用?<br />因为Java中的提供clone()方法来实现对象的克隆,所以Prototype模式实现一下子变得很简单.</p>
		<p>以勺子为例：</p>
		<table cellspacing="3" cellpadding="3" width="96%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">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 /></td>
						</tr>
				</tbody>
		</table>
		<p>有个具体实现(ConcretePrototype):</p>
		<table cellspacing="3" cellpadding="3" width="92%" border="0">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class SoupSpoon extends AbstractSpoon<br />{ <br />　　public SoupSpoon()<br />　　{<br />　　　　setSpoonName("Soup Spoon"); <br />　　}<br />}<br /></p>
										<p>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>调用Prototype模式很简单:</p>
		<p>AbstractSpoon spoon = new SoupSpoon();<br />AbstractSpoon spoon2 = spoon.clone(); </p>
		<p>当然也可以结合工厂模式来创建AbstractSpoon实例。</p>
		<p>在Java中Prototype模式变成clone()方法的使用，由于Java的纯洁的面向对象特性，使得在Java中使用设计模式变得很自然，两者已经几乎是浑然一体了。这反映在很多模式上，如Interator遍历模式。</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/104222.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-03-16 13:18 <a href="http://www.blogjava.net/hengheng123456789/articles/104222.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>