﻿<?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-每日一得-随笔分类-design</title><link>http://www.blogjava.net/alex/category/13261.html</link><description>不求多得,只求一得
about java,hibernate,spring,design,database,linux,etc.
&lt;br/&gt;&lt;br/&gt;
最近关心的内容关键字:web快速开发方案，建模,workshop studio,Ajax
</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 14:53:46 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 14:53:46 GMT</pubDate><ttl>60</ttl><item><title>谈谈 Facade与Proxy的联系与区别</title><link>http://www.blogjava.net/alex/archive/2006/10/10/74241.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 10 Oct 2006 03:09:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/10/10/74241.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/74241.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/10/10/74241.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/74241.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/74241.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2006/10/10/74241.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/74241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-10-10 11:09 <a href="http://www.blogjava.net/alex/archive/2006/10/10/74241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Facade的应用</title><link>http://www.blogjava.net/alex/archive/2006/10/09/74184.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 09 Oct 2006 14:27:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/10/09/74184.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/74184.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/10/09/74184.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/74184.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/74184.html</trackback:ping><description><![CDATA[Facade用的非常的广了，以前刚接触的时候有个误解，总觉得Facade是简单的，而它后面的支撑服务是复杂的，对于客户来说却是简单的，现在来看，不完全对，或者说只是说对了一半，因为有时候恰恰是Facade是复杂的.<br /><br />我们举一个例子，比如发送短信，我们一般就定义一个MessageService的服务类，里面只提供一个方法就行了，sendToUser(String phone,String content)<br />但是到了客户端的时候有了自己的 "方言",比如它不是关心一个抽象的用户，它只知道向教师发送短信，或者向学生发送短信，或者向家长发送短信。<br /><br />示例如下:<br /><br /><img src="http://www.blogjava.net/images/blogjava_net/alex/images/facade.png" alt="facade.png" border="0" height="277" width="250" /><br />由图中可以看到，Facade的内容非常丰富，而支撑它的服务类却很简单，在开发过程中我们一般先实现通用的ServiceA,然后根据进一步的需求做一个面向具体复杂的Facade.<br /><br /><br /><br />在Spring提供的sample里发现一个小技巧，就是Facade和ServiceA都是接口，然后提供一个实现二者的支撑类:<br /><br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> PetStoreAnnotationImpl </span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);"> PetStoreFacade, OrderService {<br /><br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> AccountDao accountDao;<br /><br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> CategoryDao categoryDao;<br /><br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> ProductDao productDao;<br /><br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> ItemDao itemDao;<br /><br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> OrderDao orderDao;<br /><br /><br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">-------------------------------------------------------------------------<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> Setter methods for dependency injection<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">-------------------------------------------------------------------------</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setAccountDao(AccountDao accountDao) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.accountDao </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> accountDao;<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setCategoryDao(CategoryDao categoryDao) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.categoryDao </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> categoryDao;<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setProductDao(ProductDao productDao) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.productDao </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> productDao;<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setItemDao(ItemDao itemDao) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.itemDao </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> itemDao;<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setOrderDao(OrderDao orderDao) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.orderDao </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> orderDao;<br />    }<br /><br /><br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">-------------------------------------------------------------------------<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> Operation methods, implementing the PetStoreFacade interface<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">-------------------------------------------------------------------------</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Account getAccount(String username) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.accountDao.getAccount(username);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Account getAccount(String username, String password) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.accountDao.getAccount(username, password);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> insertAccount(Account account) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.accountDao.insertAccount(account);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> updateAccount(Account account) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.accountDao.updateAccount(account);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> List getUsernameList() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.accountDao.getUsernameList();<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> List getCategoryList() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.categoryDao.getCategoryList();<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Category getCategory(String categoryId) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.categoryDao.getCategory(categoryId);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> List getProductListByCategory(String categoryId) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.productDao.getProductListByCategory(categoryId);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> List searchProductList(String keywords) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.productDao.searchProductList(keywords);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Product getProduct(String productId) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.productDao.getProduct(productId);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> List getItemListByProduct(String productId) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.itemDao.getItemListByProduct(productId);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Item getItem(String itemId) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.itemDao.getItem(itemId);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">boolean</span><span style="color: rgb(0, 0, 0);"> isItemInStock(String itemId) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.itemDao.isItemInStock(itemId);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> insertOrder(Order order) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.orderDao.insertOrder(order);<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.itemDao.updateQuantity(order);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Order getOrder(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> orderId) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.orderDao.getOrder(orderId);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> List getOrdersByUsername(String username) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.orderDao.getOrdersByUsername(username);<br />    }<br /><br />}</span></div><br /><br />看起来似乎不错，不过仔细想想个人认为还是不是太好,总的感觉就是层次不清晰，因为很多时候Facade和Service之间是被服务与服务的关系，所以理当分开。 同时，这个类有点倾向于"万能类"了，能分还是分开好.这和我们以前提到的dao又背离过来了（以前我们提倡一个业务一个dao,现在觉得只用一个通用的dao更合适）,这个并不矛盾，具体问题具体看待.<br /><br />欢迎各位拍砖.<br /><img src ="http://www.blogjava.net/alex/aggbug/74184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-10-09 22:27 <a href="http://www.blogjava.net/alex/archive/2006/10/09/74184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之Visitor 访问者模式</title><link>http://www.blogjava.net/alex/archive/2006/09/28/72457.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 28 Sep 2006 01:30:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/28/72457.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/72457.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/28/72457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/72457.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/72457.html</trackback:ping><description><![CDATA[
		<h3 align="center">设计模式之Visitor</h3>
		<p align="center">
				<a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com
                    2002/05/05（转载请保留）</p>
		<p align="center">
				<a href="http://www.jdon.com/mybook/index.htm" target="_blank">
						<strong>模式实战书籍《Java实用系统开发指南》</strong>
				</a>
		</p>
		<p>
				<b>Visitor访问者模式定义</b>
				<br />
                    作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.</p>
		<p>在Java中,Visitor模式实际上是分离了collection结构中的元素和对这些元素进行操作的行为.</p>
		<p>
				<b>为何使用Visitor?</b>
				<br />
Java的Collection(包括Vector和Hashtable)是我们最经常使用的技术,可是Collection好象是个黑色大染缸,本来有
各种鲜明类型特征的对象一旦放入后,再取出时,这些类型就消失了.那么我们势必要用If来判断,如:</p>
		<p>
				<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的类型.</p>
		<p>很显然,这样做的缺点代码If else if 很繁琐.我们就可以使用Visitor模式解决它.</p>
		<p>
				<b>如何使用Visitor?</b>
				<br />
                    针对上例,定义接口叫Visitable,用来定义一个Accept操作,也就是说让Collection每个元素具备可访问性.</p>
		<p>被访问者是我们Collection的每个元素Element,我们要为这些Element定义一个可以接受访问的接口(访问和被访问是互动的,只有访问者,被访问者如果表示不欢迎,访问者就不能访问),取名为Visitable，也可取名为Element。</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public interface Visitable<br />
                        {<br />
                        　　 public void accept(Visitor visitor);<br />
                        }</td>
						</tr>
				</tbody>
		</table>
		<p>被访问的具体元素继承这个新的接口Visitable：</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class StringElement implements 
                          Visitable<br />
                          {<br />
                          　　 private String value;<br />
                          　　 public StringElement(String string) {<br />
                          　　 　　 value = string;<br />
                          　　 }</p>
										<p>　　 public String getValue(){<br />
                          　　 　　 return value;<br />
                          　　 }</p>
										<p>
												<br />
                          　　 //定义accept的具体内容 这里是很简单的一句调用<br />
                          　　 public void accept(Visitor visitor) {<br />
                          　　 　　 visitor.visitString(this);<br />
                          　　 }<br />
                          }</p>
										<p>
												<br />
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>上面是被访问者是字符串类型，下面再建立一个Float类型的：</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class FloatElement implements 
                          Visitable<br />
                          {<br />
                          　　 private Float value;<br />
                          　　 public FloatElement(Float value) {<br />
                          　　 　　 this.value = value;<br />
                          　　 }</p>
										<p>　　 public Float getValue(){<br />
                          　　 　　 return value;<br />
                          　　 }</p>
										<p>
												<br />
                          　　 //定义accept的具体内容 这里是很简单的一句调用<br />
                          　　 public void accept(Visitor visitor) {<br />
                          　　 　　 visitor.visitFloat(this);<br />
                          　　 }<br />
                          }</p>
										<p>
												<br />
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>我
们设计一个接口visitor访问者，在这个接口中,有一些访问操作，这些访问操作是专门访问对象集合Collection中有可能的所有类，目前我们假
定有三个行为：访问对象集合中的字符串类型；访问对象集合中的Float类型；访问对象集合中的对象集合类型。注意最后一个类型是集合嵌套，通过这个嵌套
实现可以看出使用访问模式的一个优点。</p>
		<p>接口visitor访问者如下：</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public interface Visitor<br />
                          {<br /><br />
                          　　 public void visitString(StringElement stringE);<br />
                          　　 public void visitFloat(FloatElement floatE);<br />
                          　　 public void visitCollection(Collection collection); 
                          <br /><br />
                          }<br /></p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>访问者的实现:</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>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 />
                          　　 ｝</p>
										<p>　　 public void visitString(StringElement stringE) {<br />
                          　　 　　 System.out.println("'"+stringE.getValue()+"'");<br />
                          　　 } <br />
                          　　 public void visitFloat(FloatElement floatE){<br />
                          　　 　　 System.out.println(floatE.getValue().toString()+"f");<br />
                          　　 } </p>
										<p> }</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>在上面的visitCollection我们实现了对Collection每个元素访问,只使用了一个判断语句,只要判断其是否可以访问.</p>
		<p>StringElement只是一个实现，可以拓展为更多的实现，整个核心奥妙在accept方法中，在遍历Collection时，通过相应的accept方法调用具体类型的被访问者。这一步确定了被访问者类型，</p>
		<p>如果是StringElement，而StringElement则回调访问者的visiteString方法，这一步实现了行为操作方法。</p>
		<p>客户端代码：</p>
		<table bgcolor="#cccccc" border="0" cellpadding="2" cellspacing="2" width="80%">
				<tbody>
						<tr>
								<td>
										<p>Visitor visitor = new ConcreteVisitor();<br /><br />
                          StringElement stringE = new StringElement("I am 
                          a String");<br />
                          visitor.visitString(stringE);</p>
										<p>Collection list = new ArrayList();<br />
                          list.add(new StringElement("I am a String1")); 
                          <br />
                          list.add(new StringElement("I am a String2")); 
                          <br />
                          list.add(new FloatElement(new Float(12))); <br />
                          list.add(new StringElement("I am a String3")); 
                          <br />
                          visitor.visitCollection(list);</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>客户端代码中的list对象集合中放置了多种数据类型，对对象集合中的访问不必象一开始那样，使用instance of逐个判断，而是通过访问者模式巧妙实现了。</p>
		<p>至此,我们完成了Visitor模式基本结构.</p>
		<p>
				<b>使用Visitor模式的前提</b>
				<br />
                    使用访问者模式是对象群结构中(Collection) 中的对象类型很少改变。</p>
		<p>在两个接口Visitor和Visitable中,确保Visitable很少变化,也就是说，确保不能老有新的Element元素类型加进来，可以变化的是访问者行为或操作，也就是Visitor的不同子类可以有多种,这样使用访问者模式最方便.</p>
		<p>如果对象集合中的对象集合经常有变化, 那么不但Visitor实现要变化，Visistable也要增加相应行为，GOF建议是,不如在这些对象类中直接逐个定义操作，无需使用访问者设计模式。</p>
		<p>但是在Java中，Java的Reflect技术解决了这个问题，因此结合reflect反射机制，可以使得访问者模式适用范围更广了。</p>
                  Reflect技术是在运行期间动态获取对象类型和方法的一种技术,具体实现参考Javaworld的<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip98.html" target="_blank">英文原文</a>.<img src ="http://www.blogjava.net/alex/aggbug/72457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-28 09:30 <a href="http://www.blogjava.net/alex/archive/2006/09/28/72457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]一个软件设计的全过程(基于UML)</title><link>http://www.blogjava.net/alex/archive/2006/09/22/71297.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Fri, 22 Sep 2006 05:16:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/22/71297.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/71297.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/22/71297.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/71297.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/71297.html</trackback:ping><description><![CDATA[key words:软件设计 建模 UML<br /><br />这篇文章以前就看到了，后来再想看的时候居然找不到了，感觉写的不错，作为想把软件开发往深里整地朋友有借鉴作用。<br /><br />转自<a href="http://meyegg.cnblogs.com/archive/2006/04/13/374128.html">这里</a><br /><br />前段时间把一个界面框架完成了，今天基于这个框架开发一个小模块，在这里把这个模块设计的全过程记录下来，希望大家讨论并指正。<br /><br />一、起因<br /><br />公
司交给我一个任务，为测试员写一个手机模拟界面，以方便她们的手机短信测试。过去她们都是用MC4J直接调用公司服务器的MBean服务来模拟进行测试，
以验证我们整个系统平台。这种测试主要是检查收发短信是否正常，而我的要做的工作就是，让她们在测试的时候更方便更直观。<br /><br />二、需求<br /><br />我和测试员陈MM（也就是软件的使用者）约定了一个时间，大家一起来讨论这个软件的需求。<br /><br />1、首先，我大概了解了一下她们的测试工作，知道我要做个什么东东。<br /><br />2、然后我回去思考了一下，再次找她详细了解其测试的具体步骤，并在一张<strong>白纸</strong>上以UML用例图的方式，记录下需求的功能。<strong>用例是什么？用例就是需求，就是你的软件应该具有的功能</strong>，当然用例图只是概括性的对功能进行了描述。<br /><br />3、最后，我坐在我的电脑前开始用MagicDraw UML来画用例图（我不喜欢用Rose，那玩意太笨重了，界面友好性也不好）。在画用例图的时候，我发现了一些隐含的功能，这些是陈MM在和我做需求时没有考虑到的<strong>（注：开发者应该为用户挖掘隐含需求）</strong>。我和陈MM一一确定了这些我新发现的需求，最后得到如下的用例图。<br /><br />（1）手机前台测试操作的用例图（说明：include是指某用例<strong>包含(include)</strong>子用例）<br /><br /><img style="width: 623px; height: 330px;" alt="[用例]手机.jpg" src="../../images/blogjava_net/chengang/others/%5B%E7%94%A8%E4%BE%8B%5D%E6%89%8B%E6%9C%BA.jpg" border="0" height="410" width="1429" /><br /> （2）后台管理<br /><img alt="[用例]后台管理.jpg" src="../../images/blogjava_net/chengang/others/%5B%E7%94%A8%E4%BE%8B%5D%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86.jpg" border="0" height="258" width="392" /><br /><br /><br />三、界面设计<br /><br />接下来是界面设计。既然是手机模拟，我很自然就拿我的motorola手机的操作界面来做参考。不过这里应该注意到，手机操作环境和电脑操作环境不尽相同（比如说电脑有鼠标，还有键盘可以输入文字），所以没有必要唯妙唯肖的完全模枋，还是以使用者操作方便为主。<br /><br />界
面设计是很重要的一步，不要一上来就写程序，一定要先做到心中有个大概，否则返工的可能性就很大。而且，把界面拿出来给客户看，客户也就能做到心中有数，
还能尽早提出一些新需求和意见来。千万不要等到软件做完了再拿给客户看，到时客户看了如果要修改，那就做太多白费工了。<br /><br />由于软件界面相对简单，陈ＭＭ基本没有提修改意见，但这不是个好兆头。不过极限编程就是要拥抱变化不是^_^。咱不怕她改，只要大致的界面她能定下来就行了。<br /><br />界面我喜欢用Visio来画，当然也听说有人喜欢用ＶＢ来快速构建界面原型的，看个人喜好了。整个界面如下：<br /><img alt="[界面设计]手机.jpg" src="../../images/blogjava_net/chengang/others/%5B%E7%95%8C%E9%9D%A2%E8%AE%BE%E8%AE%A1%5D%E6%89%8B%E6%9C%BA.jpg" border="0" height="611" width="556" /><br /><br /><br /><br />这个是后台管理界面<br /><img alt="[界面设计]号码管理.jpg" src="../../images/blogjava_net/chengang/others/%5B%E7%95%8C%E9%9D%A2%E8%AE%BE%E8%AE%A1%5D%E5%8F%B7%E7%A0%81%E7%AE%A1%E7%90%86.jpg" border="0" height="480" width="478" /><br /><br /><br /><br />四、类图<br /><br />类图反映了软件的数据模型。在设计数据模型，我参考了界面设计图和用例图，找出一个个的类。然后参照用例图的一个个功能，设计出了各类的属性和方法。设计初始的类图当然不可能很详细，但至少应该看到个大概。有错误不要紧，后期可以慢慢修正，但大体关系就算定下来了。<br /><br /><strong>Neil（公司ＣＴＯ，一个40岁左右的真正的资深程序员）说：看一个软件的设计主要看两个类：类图和时序图。类图确定了软件数据模型的静态关型，时序图则是数据模型的动态关系。</strong><br /><br />类图如下，看英文大致可以知道类／属性／方法的含义和作用了，就不一一介绍了。<br /><br /><br /><img alt="[类图].jpg" src="../../images/blogjava_net/chengang/others/%5B%E7%B1%BB%E5%9B%BE%5D.jpg" border="0" height="562" width="625" /><br /><br /><br /><br />五、时序图<br /><br />时序图是本文最后一个图，时序图表明了<strong>用例图</strong>中各功能的实现方案，同时也反应了<strong>类图</strong>中各类的交互关系。以后程序的逻辑和时序图基本一致。不过，有些人会去画得很详细的时序图，详细到都快赶上伪代码级别了，我觉得这没必要。我把时序图看做反映自己思路的大概过程，所以也就画个大概。<br /><br />我认为时序图要简洁易懂，这样以后你的后继维护者，拿到这个软件的时序图（当然也包括用例图、类图），就能明白你的大概设计思路。另外，画时序图也能整理自己的思路，同时还可以对类图的设计进行验证。在画这个时序图的过程中，我就纠正了在类图中的几处考虑不周的地方。<br /><br />总结：时序图可以（１）整理思路（２）验证类的设计（３）是很好的软件文档，对维护者理解代码很有帮助。<br /><br />这里仅给出其中几个时序图（实际上我也没有把用例都画完，有些类似的简单的，就忽略了）<br /><br />（１）新增一个手机号码<br /><img alt="[时序图]add phone number.jpg" src="../../images/blogjava_net/chengang/others/%5B%E6%97%B6%E5%BA%8F%E5%9B%BE%5Dadd%20phone%20number.jpg" border="0" height="327" width="583" /><br /><br />（２）关机<br /><img alt="[时序图]power off.jpg" src="../../images/blogjava_net/chengang/others/%5B%E6%97%B6%E5%BA%8F%E5%9B%BE%5Dpower%20off.jpg" border="0" height="255" width="293" /><br />（３）开机<br /><img alt="[时序图]power on.jpg" src="../../images/blogjava_net/chengang/others/%5B%E6%97%B6%E5%BA%8F%E5%9B%BE%5Dpower%20on.jpg" border="0" height="337" width="407" /><br />（４）发送短信<br /><img alt="[时序图]send message.jpg" src="../../images/blogjava_net/chengang/others/%5B%E6%97%B6%E5%BA%8F%E5%9B%BE%5Dsend%20message.jpg" border="0" height="381" width="405" /><br /><br /><br /><br />到这里设计阶段就完成了，用时一天。下一步是编码，将应用ＴＤＤ先写测试代码的方式来写代码，下次再介绍了。<br /><br /><br /><h5><font size="4">作者简介</font></h5><p>陈刚，广西桂林人，著作有《Eclipse从入门到精通》<br />您可以通过其博客了解更多信息和文章：<a href="http://www.chengang.com.cn/" target="_blank" &#111;nfocus="this.blur()"><font color="#000033">http://www.ChenGang.com.cn</font></a><br />版权声明：本博客所有文章仅适用于非商业性转载，并请在转载时注明出处及作者的署名。</p><img src ="http://www.blogjava.net/alex/aggbug/71297.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-22 13:16 <a href="http://www.blogjava.net/alex/archive/2006/09/22/71297.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]成为软件架构师</title><link>http://www.blogjava.net/alex/archive/2006/09/22/71296.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Fri, 22 Sep 2006 05:14:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/22/71296.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/71296.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/22/71296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/71296.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/71296.html</trackback:ping><description><![CDATA[key words:软件架构师<br />转自<a href="/chengang/archive/2006/09/16/70067.html">here</a><br /><br />现在软件架构师满天飞，是个写代码的都称自己为软件架构师，就象开个公司管上四五号人就给自己按个CEO头衔一样，着实让人好笑。于是到网上GOOGLE了一下看看软件构架师具体是个啥东东，有想做货真价实的构架师，就朝着那方向努力吧。网摘如下：<br /><br /><span style="color: rgb(0, 0, 0);">软件架构师的职责：将客户的需求转换为规范的开发计划及文本，并制定这个项目的总体架构，指导整个开发团队完成这个计划。<br /><br /><strong>软件架构师的具体工作：<br /></strong>    (</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)在需求阶段，软件架构师主要负责理解和管理非功能性系统需求，比如软件的可维护性、性能、复用性、可靠性、有效性和可测试性等等，此外，架构师还要经常审查和客户及市场人员所提出的需求，确认开发团队所提出的设计；<br />    (</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">)在需求越来越明确后，架构师的关注点开始转移到组织开发团队成员和开发过程定义上；<br />    (</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">)在软件设计阶段，架构师负责对整个软件体系结构、关键构件、接口和开发政策的设计；<br />    (</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">)在编码阶段，架构师则成为详细设计者和代码编写者的顾问，并且经常性地要举行一些技术研讨会、技术培训班等；<br />    (</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">)随着软件开始测试、集成和交付，集成和测试支持将成为软件架构师的工作重点；<br />    (</span><span style="color: rgb(0, 0, 0);">6</span><span style="color: rgb(0, 0, 0);">)在软件维护开始时，软件架构师就开始为下一版本的产品是否应该增加新的功能模块进行决策。<br /> <br /><strong>软件架构师的要求</strong><br />      (</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)必须对开发技术非常了解，具有丰富的软件设计与开发经验，关键时候能对技术的选择作出及时、有效的决定。<br />      (</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">)有良好的组织管理能力：沟通、领导、团队协作<br />      (</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">)构件通信机制方面的知识:远程调用、JAVARMI、CORBA、COM</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">DCOM、各种标准的通信协议、网络服务、面对对象数据库、关系数据库等等<br /><br /><strong>成长为软件架构师的几个阶段：<br /></strong>     <font color="#ff0000"> </font><font color="#0000ff">(</font></span><font color="#0000ff"><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)构架师胚胎（程序员）：语言基础、设计基础、通信基础等，内容包括java、c、c</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">、uml、RUP、XML、socket通信（通信协议）<br />      (</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">)构架师萌芽（高级程序员）：分布式系统组建等内容，包括分布式系统原理、ejb、corba、com</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">com</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">、webservice、网络计算机、高性能并发处理等<br />      (</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">)构架师幼苗（设计师）：透彻掌握设计模式，包括设计模式（c</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">版本、java版本）、ejb设计模式、J2EE构架、UDDI、软件设计模式等。此期间，最好能够了解软件工程在实际项目中的应用以及小组开发、团队管理</span></font><img src ="http://www.blogjava.net/alex/aggbug/71296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-22 13:14 <a href="http://www.blogjava.net/alex/archive/2006/09/22/71296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DAO模式演变</title><link>http://www.blogjava.net/alex/archive/2006/09/21/71123.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 21 Sep 2006 08:05:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/21/71123.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/71123.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/21/71123.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/71123.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/71123.html</trackback:ping><description><![CDATA[key words: DAO模式<br /><br />今天在看一篇文章时提到了DAO，这个东西以前也经常接触，突然想回顾一下，于是打开Appfuse里看看dao模式（记忆中appfuse里就是很多的dao）<br /><br />截图如下:<br /><img src="http://www.blogjava.net/images/blogjava_net/alex/images/appfusedao.png" alt="appfusedao.png" border="0" height="382" width="776" /><br /><br />很清楚，左边的部分是基础模块，原意是想让右边的DAO和实现能够重用左边的，可是我找了半天也没看到需要重用左边的东西，因为在client调用的所有方法中都是明确的getUser或removeUser,就是没有getObject或者removeObject,那么不禁要问，左边的基础dao和它的实现还有什么意义呢？所以我的第一想法就是把左边的去掉得了，还好，果然有支持我想法的做法，打开springside,我们看到如下的结构:<br />截图2<br /><img src="http://www.blogjava.net/images/blogjava_net/alex/images/springside.png" alt="springside.png" border="0" height="331" width="834" /><br />这里的做法更厉害，连interface也不要了，不过效果确实是很简洁，在bookmanager里完全重用了左边的基本方法 ：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Book get(Integer id) {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> (Book) </span><span style="color: rgb(0, 0, 255);">super</span><span style="color: rgb(0, 0, 0);">.get(id);<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> save(Book book) {<br />        </span><span style="color: rgb(0, 0, 255);">super</span><span style="color: rgb(0, 0, 0);">.save(book);<br />        logger.info(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">保存图书.图书详情:</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> book.toString());<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> remove(Integer id) {<br />        </span><span style="color: rgb(0, 0, 255);">super</span><span style="color: rgb(0, 0, 0);">.remove(id);<br />        logger.info(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">删除图书.图书ID:</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> id);<br />    }</span></div><br />这是一个更务实的做法，如果你的项目并不是那么那么的复杂完全可以这么做，当然要说其有什么缺点显然和没有了interface的天生属性决定了的，不可强求，若你对测试隔离面向接口以及你能想到的所有关于interface的好处，那就用你自己的方式吧。<br /><br />现在我在想一个问题，难道appfuse里的继承的基本关于object的做法就没有地方可用了么？ <br /><br /><hr size="2" width="100%" />其时正好碰到java视线这一篇文章有点相关，你可以参考一下: <br /><a target="_blank" href="http://www.javaeye.com/topic/20216"><span style="color: rgb(0, 102, 153); font-weight: bold; font-size: 10pt;">用DAO模式有什么好处？</span></a><br /><hr size="2" width="100%" /><br /><font color="#ff0000">ps:<br />以前是一个基本的dao,然后n个业务dao继承于这个基本dao,现在提供一个通用dao,每个要用到的地方直接继承用就是了，更务实了!<br />不过，有一个小小的瑕疵，就是对于service中类似getUserByName或者getPeopleByEmail方法中需要提供给dao一个sql语句，从mvc的角度看，在service中看到了db层，有点不雅，不过综合来看这个还是可以或略，不要专牛角尖嘛  :)</font><br /><img src ="http://www.blogjava.net/alex/aggbug/71123.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-21 16:05 <a href="http://www.blogjava.net/alex/archive/2006/09/21/71123.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]做设计的步骤</title><link>http://www.blogjava.net/alex/archive/2006/09/20/70678.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 20 Sep 2006 01:02:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/20/70678.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/70678.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/20/70678.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/70678.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/70678.html</trackback:ping><description><![CDATA[key words: 如何做设计 设计步骤<br />转自<a href="http://www.javaeye.com/topic/1464?page=3">robin</a><br /><br />一。需求分析(抽象Use case + 分析Use case之间的关系)<br /><p>分析软件需求，以用户的角度来使用软件，找出发生的scenerio，<font color="#ff1493">抽象成为一个一个Use Case，分析出Use Case之间的关系</font>，这一步是非常重要的，这一步做好了，设计就成功了一半。Use Case的抽象有一些可以遵循的原则，这里不详细谈。</p><p>然后用语言描述每一个Use Case，描述用户使用一个Use Case发生的主事件流以及异常流。</p><p>这样就完成了需求分析阶段。</p><p>二。概要设计(找出实体 + 分析实体类之间的关系 + 提取控制类 + 画序列图)<br /></p><p>接下来做概要设计，针对每个Use Case，读Use Case的描述，<font color="#ff1493">看事件流，找出所有的实体类</font>，这也有一些可以遵循的原则，例如<b>找出所有的名词，画表格排除</b>等等方法。</p><p><font color="#0000ff">然后分析实体类之间的关系，是包含，聚合还是依赖，是1：1，还是1：n，还是其他</font>....，根据这些关系，就可以得出实体类和别的实体类想关联的属性，然后再找出每个实体类本身重要的属性。</p><p>然后再次分析Use
Case的事件流，一方面check实体类的设计是否合理，另一方面你可以找出动词，<font color="#ff1493">分析对实体类的控制逻辑，这样就可以可以设计出业务控制类</font>，一般你可
以一个实体类一个控制类，也可以业务逻辑相关的实体类由一个Facade Session
Bean(非EJB含义)来统一控制，这里面的控制类的颗粒度就由你自己来掌握了。<font color="#0000ff">一般来说先可以设计一些细颗粒度的控制类</font>，然后再按照模块，用粗粒度封
装细颗粒度的控制类，提供给Web层一个Facade。</p><p><font color="#0000ff">然后你可以画序列图，就是用序列图来表达事件流</font>，在这个过程中，你需要不断回到类图，给控制类添加方法，而序列图就是控制类的方法调用。</p><p>至此，你已经在Rose里面完成了概要设计，当然你不可能一次设计完善，会有很多次迭代，因此你不能一开始把类设计的太详细，只抓住主要的属性和方法，特别需要注意的是，是抽象的设计，不要用具体的编程语言来表达类。</p><p>三。实施(结合xdoclet和Schema工具自动生成代码)<br /></p><p>然后你就可以抛开Rose了，转到Eclipse+Togehter里面，根据那些类，规划一下package层次，然后在Together里面进行类的详细设计，所有需要的属性一一写上，当然你还是不可能一下把所有的属性方法写全，不过没有关系，把重要的写好就行了。</p><p>然后类框架已经生成好了，<font color="#ff1493">给所有的实体类加上xdoclet，然后生成hbm，然后用Hibernate的ExportScheme生成DDL，</font>运行一遍自动创建好所有的表。这样所有的实体相关类全部做好了。</p><p>你现在就集中精力把控制类那些方法里面的代码填写上就OK了，在这个过程，你会发现有些实体类缺属性，没有关系，加上属性，然后写好xdoclet，运行一遍，自动生成hbm，自动创建好表，然后继续写你的方法，也有可能你发现控制类缺方法，那么就加上。</p><p>基本上实体类就是getter/setter，和少量的实体相关方法，所有的控制逻辑都写在控制类里面。</p><p>最后你的软件就基本写好了，用Eclipse生成好一堆你的testCase运行测试，反复修改，除bug。</p><p>看看使用OOAD的设计思路，是多么的爽的事情阿！<b>你只需要把精力放到Use
Case的抽象</b>，实体类的关系总结，控制类的归纳。而当你使用Eclipse＋Together之后，你所需要写的代码只不过是控制类的方法实现代码，其
他的都已经生成好了。另外可能需要写少量工具类。</p><br /><img src ="http://www.blogjava.net/alex/aggbug/70678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-20 09:02 <a href="http://www.blogjava.net/alex/archive/2006/09/20/70678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Effective Java读书笔记</title><link>http://www.blogjava.net/alex/archive/2006/09/11/69002.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 11 Sep 2006 10:14:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/11/69002.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/69002.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/11/69002.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/69002.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/69002.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 终于翻开这本James都称赞的java经典书籍了，发现比一般的英语书籍要难懂一些。但是里面的Item都是非常实用的，是java程序员应该理解的。 Creating and Destroying ObjectItem 1:考虑用静态工厂方法替代构造器例如：public static Boolean valueOf(boolean b)     {          return (b?Boolean...&nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2006/09/11/69002.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/69002.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-11 18:14 <a href="http://www.blogjava.net/alex/archive/2006/09/11/69002.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]从工作流状态机实践中总结状态模式使用心得</title><link>http://www.blogjava.net/alex/archive/2006/09/09/68672.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sat, 09 Sep 2006 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/09/68672.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68672.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/09/68672.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68672.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68672.html</trackback:ping><description><![CDATA[
		<h3 align="center">从工作流状态机实践中总结状态模式使用心得</h3>
		<p align="center">
				<a href="http://www.jdon.com/jive/profile.jsp?user=2" title="彭晨阳(网名: 板桥里人)">
						<b>banq</b>
				</a> http://www.jdon.com Dec 7, 2003 12:10 AM
                <a href="http://www.jdon.com/jive/post.jsp?forum=91&amp;thread=10981&amp;message=4743784&amp;reply=true"><img src="http://www.jdon.com/jive/images/reply.gif" alt="回复此消息" border="0" height="17" hspace="3" width="17" /></a><font><a href="http://www.jdon.com/jive/post.jsp?forum=91&amp;thread=10981&amp;message=4743784&amp;reply=true" title="回复此消息">回复</a></font></p>
                
状态模式好像是很简单的模式，正因为状态好像是个简单的对象，想复杂化实现设计模式就不是容易，误用情况很多。<br /><br />我个人曾经设计过一个大型游戏系统的游戏状态机，游戏状态可以说是游戏设计的主要架构，但是由于系统过分复杂<br />和时间仓促，并没有真正实现状态模式。<br /><br />目前在实现一个电子政务项目中，需要进行流程状态变化，在电子政务设计中，我发现，如果一开始完全按照工作流<br />规范开发，难度很大，它和具体项目实践结合无法把握，而且工作流规范现在有wfmc，还有bpml，选择也比较难。因<br />此，我决定走自创的中间道路。<br /><br />因为，我需要做一个状态机API，或者说状态机框架，供具体系统调用：类如公文流转应用或信息发报送应用等。<br /><br />好的状态模式必须做到两点：<br />1. 状态变化必须从外界其它逻辑划分出来。<br />2. 状态必须可方便拓展，对其它代码影响非常小。<br /><br />要做到这两点，必须先明确状态变化机制，状态变化实际是由Event事件驱动的，可以认为是Event-condition-State，<br />在MVC模式一般是Event-condition-Action实现。状态模式需要封装的是Event-condition-State中的condition-State<br />部分。<br /><br />清晰理解状态和流程的关系也非常重要，因为状态不是孤立的，可以说和流程是点和线的关系，状态从一个方面说明<br />了流程，流程是随时间而改变，状态是截取流程某个时间片。因此，必须明白使用状态模式实现状态机实际是为了更<br />好地表达和说明流程。<br /><br />状态和流程以及事件的关系如下：<br /><br /><br />                 |Event<br />___currentState__|______newState___<br /><br /><br /><br /><br />图中表示了是事件改变了流程的状态，在业务逻辑中，经常发生的是事件，如果不使用状态模式，需要在很多业务逻<br />辑处实现事件到状态判定和转换，这有很多危险性。<br /><br />最大的危险是系统没有一个一抓就灵的主体结构，以那个游戏系统为例，在没有状态模式对状态提炼的情况下，状态<br />改变由每个程序员想当然实现，导致每个程序员开发的功能在整合时就无法调试，因为这个程序员可能不知道那个程<br />序员的代码在什么运行条件下改变了游戏状态，结果导致自己的代码无法运行。<br /><br />这种现象实际上拒绝了项目管理的协作性，大大地拖延项目进度（程序员之间要反复商量讨论对方代码设计）。从这<br />一点也说明，一个好的架构设计是一个项目快速成功完成的基础技术保证，没有这个技术基础，再先进的项目管理手<br />段也是没有效率的，或者是笨拙的。<br /><br />状态模式对于很多系统来说，确实是架构组成一个重要部分。<br /><br />下面继续讨论如何实现一个好的状态模式，为了实现好的状态模式，必须在状态模式中封装下面两个部分：<br />1. 状态转换规则（行为）<br />2. 状态属性（属性）<br /><br />状态转换行为有两种划分标准：<br />1. run和next两个行为，run是当前状态运行行为，next是指在Event参与下，几种可能转向的下一个状态。<br />2. stateEnter和stateExit， 状态进入和状态退出。<br /><br />如果用进入一个个房间来表示状态流程的话， 第一种分析是只重视着“在房间里”和“如何转入下一个房间”，这两种行<br />为一旦确定，可以被反复使用，进而一个流程的状态切换可以全部表达出来。<br /><br />第二中分析方法有所区别，只重视进入房间和离开房间这个两个行为，同样，这种模型也可以被反复利用在其它房间，<br />一个流程的状态切换也可以全部表达出来。<br /><br />具体选择取决于你的需求，比如，如果你在进入一个状态开始，要做很多初始化工作，那么第二种模型就很适合。<br /><br />状态变化都离不开一个主体对象，主体对象可以说包含状态变化（行为）和状态属性（属性），假设为StateOwner，<br />StateOwner有两个部分组成：Task/事情和状态。任何一个Task/事情都会对应一个状态。<br /><br />这样，我们已经抽象出两个主要对象：状态State和StateOwner。<br /><br />为了封装状态变化细节，我们可以抽象出一个状态机StateMachine来专门实现状态根据事情实现转换。<br /><br />这样，客户端外界通过状态机可访问状态模式这个匣子。在实践中，外界客户端需要和状态机实现数据交换，我们把<br />它也分为两种：属性和行为。<br /><br />其中属性可能需要外界告诉状态状态变化的主体对象Task，解决状态的主人问题，是谁的问题；行为可能是需要持久<br />化当前这个主体对象的状态到数据库。<br /><br />这两种数据交换可以分别通过StateOwner和StateMachine与整个状态机实现数据交换，这样，具体状态和状态切换也<br />和外界实现了解耦隔离。<br /><br />因此好的状态模式实现必须有下列步骤：<br />（1）将每个状态变成State的子类，实现每个状态对象化。<br />（2）在每个状态中，封装着进入下一个状态可能规则，这些规则是状态变化的核心，换句话说，统一了状态转换的规则。<br />     具体可采取run和next这样的转换行为。<br /><br />下面是一个子状态代码：<br /><br /><br /><b>public</b><b>class</b> Running <b>extends</b> StateT{<br /><br /><font color="#0000aa">//</font><font color="black"><br /><b>public</b><b>void</b> run(StateOwner stateOwner){<br />     stateOwner.setCurrentState(<b>this</b>);<br />  }<br /><br /></font><font color="#0000aa">//转换到下一个状态的规则</font><font color="black"><br /></font><font color="#0000aa">//当前是Running状态，下一个状态可能是暂停、结束或者强制退出等</font><font color="black"><br /></font><font color="#0000aa">//状态，但是绝对不会是Not_Started这样的状态</font><font color="black"><br /></font><font color="#0000aa">//转换规则在这里得到了体现。</font><font color="black"><br /><b>public</b> State next(Event e) {<br /><b>if</b>(transitions == <b>null</b>){<br />       addEventState(<b>new</b> EventImp(</font><font color="#00bb00">"PAUSE"</font><font color="black">), <b>new</b> Suspended());<br />       addEventState(<b>new</b> EventImp(</font><font color="#00bb00">"END"</font><font color="black">), <b>new</b> Completed());<br />       addEventState(<b>new</b> EventImp(</font><font color="#00bb00">"STOP"</font><font color="black">), <b>new</b> Aborted());<br />    }<br /><b>return</b><b>super</b>.next(e);<br />  }<br /><br />}     <br /><br /><br /><br />外界直接调用 StateMachine的关键方法transition；实行状态的自动转变。  <br /><br /><br /><b>public</b><b>class</b> StateMachine {<br /><br /></font><font color="#0000aa">/**<br />   * 状态切换<br />   * 根据Event参数，运行相应的状态。<br />   * 1. 获得当前状态<br />   * 2. 使用当前状态的next()转换<br />   *                  |Event<br />   * ___currentState__|______newState___<br />   *<br />   * @param inputs<br />   */</font><font color="black"><br /><b>public</b><b>final</b><b>void</b> transition(String taskid, Event e) throws Exception {<br />    State currentState = readCurrentState(taskid); </font><font color="#0000aa">//从数据库获得当前状态</font><font color="black"><br />    StateOwner stateOwner = <b>new</b> StateOwner(taskid, currentState);<br /></font><font color="#0000aa">//转换状态</font><font color="black"><br />    currentState = currentState.next(e);<br /><b>if</b> (currentState != <b>null</b>) {<br />      currentState.run(stateOwner);<br />      saveCurrentState(stateOwner); </font><font color="#0000aa">//保存当前状态</font><font color="black"><br />    }<br />  }<br /><br />} </font><img src ="http://www.blogjava.net/alex/aggbug/68672.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-09 10:43 <a href="http://www.blogjava.net/alex/archive/2006/09/09/68672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之state 状态模式</title><link>http://www.blogjava.net/alex/archive/2006/09/09/68671.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sat, 09 Sep 2006 02:42:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/09/68671.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68671.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/09/68671.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68671.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68671.html</trackback:ping><description><![CDATA[
		<h3 align="center">设计模式之State</h3>
		<p align="center">
				<a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com 2002/4/6/</p>
		<p align="center">
				<a href="http://www.jdon.com/mybook/index.htm" target="_blank">
						<strong>模式实战书籍《Java实用系统开发指南》</strong>
				</a>
		</p>
		<p>
				<i>
						<b>State模式的定义</b>
				</i>: 不同的状态,不同的行为;或者说,每个状态有着相应的行为.</p>
		<p>
				<i>
						<b>何时使用</b>
				</i>?<br />
                    State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 
                    进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了.</p>
		<p>不
只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上
property属性含义的字段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State.<br /></p>
		<p>
				<i>
						<b>是否使用?</b>
				</i>
				<br />
                    在实际使用,类似开关一样的状态切换是很多的,但有时并不是那么明显,取决于你的经验和对系统的理解深度.</p>
		<p>这里要阐述的是"开关切换状态" 和" 一般的状态判断"是有一些区别的, " 
                    一般的状态判断"也是有 if..elseif结构,例如:</p>
		<p>　　　　if (which==1) state="hello";<br />
                    　　　　else if (which==2) state="hi";<br />
                    　　　　else if (which==3) state="bye";<br /></p>
		<p>这是一个 " 一般的状态判断",state值的不同是根据which变量来决定的,which和state没有关系.如果改成:</p>
		<p>　　　　if (state.euqals("bye")) state="hello";<br />
                    　　　　else if (state.euqals("hello")) state="hi";<br />
                    　　　　else if (state.euqals("hi")) state="bye";<br /></p>
		<p>这就是 "开关切换状态",是将state的状态从"hello"切换到"hi",再切换到""bye";在切换到"hello",好象一个旋转开关,这种状态改变就可以使用State模式了.</p>
		<p>如
果单纯有上面一种将"hello"--&gt;"hi"--&gt;"bye"--&gt;"hello"这一个方向切换,也不一定需要使用State模
式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了.</p>
		<p>请看下例:</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class Context{</p>
										<p>　　private Color state=null;</p>
										<p>　　public void push(){</p>
										<p>　　　　//如果当前red状态 就切换到blue<br />
                          　　　　if (state==Color.red) state=Color.blue;<br /><br />
                          　　　　//如果当前blue状态 就切换到green<br />
                          　　　　else if (state==Color.blue) state=Color.green;<br /><br />
                          　　　　//如果当前black状态 就切换到red<br />
                          　　　　else if (state==Color.black) state=Color.red;<br /><br />
                          　　　　//如果当前green状态 就切换到black<br />
                          　　　　else if (state==Color.green) state=Color.black;<br />
                          　　　　<br />
                          　　　　Sample sample=new Sample(state);<br />
                          　　　　sample.operate();<br />
                          　　}</p>
										<p>　　public void pull(){<br /><br />
                          　　　　//与push状态切换正好相反</p>
										<p>　　　　if (state==Color.green) state=Color.blue;<br />
                          　　　　else if (state==Color.black) state=Color.green;<br />
                          　　　　else if (state==Color.blue) state=Color.red;<br />
                          　　　　else if (state==Color.red) state=Color.black;<br /><br />
                          　　　　Sample2 sample2=new Sample2(state);<br />
                          　　　　sample2.operate(); <br />
                          　　}</p>
										<p>}</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它.</p>
		<p>另外注意:但就上例,state的变化,只是简单的颜色赋值,这个具体行为是很简单的,State适合巨大的具体行为,因此在,就本例,实际使用中也不一定非要使用State模式,这会增加子类的数目,简单的变复杂.</p>
		<p>例如: 银行帐户, 经常会在Open 状态和Close状态间转换.</p>
		<p>例如: 经典的TcpConnection, Tcp的状态有创建 侦听 关闭三个,并且反复转换,其创建 侦听 关闭的具体行为不是简单一两句就能完成的,适合使用State</p>
		<p>例如:信箱POP帐号, 会有四种状态, start HaveUsername Authorized quit,每个状态对应的行为应该是比较大的.适合使用State</p>
		<p>例如:在工具箱挑选不同工具,可以看成在不同工具中切换,适合使用State.如 具体绘图程序,用户可以选择不同工具绘制方框 
                    直线 曲线,这种状态切换可以使用State.</p>
		<p>
				<i>
						<b>如何使用</b>
				</i>
				<br />
                    State需要两种类型实体参与:</p>
		<p>1.state manager 状态管理器 ,就是开关 ,如上面例子的Context实际就是一个state manager, 
                    在state manager中有对状态的切换动作.<br />
                    2.用抽象类或接口实现的父类,,不同状态就是继承这个父类的不同子类.</p>
		<p>以上面的Context为例.我们要修改它,建立两个类型的实体.<br /><b>第一步: 首先建立一个父类:</b></p>
		<table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public abstract class State{</p>
										<p>　　public abstract void handlepush(Context c);<br />
                          　　public abstract void handlepull(Context c);<br />
                          　　public abstract void getcolor();</p>
										<p>}</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>父类中的方法要对应state manager中的开关行为,在state manager中 本例就是Context中,有两个开关动作push推和pull拉.那么在状态父类中就要有具体处理这两个动作:handlepush() 
                    handlepull(); 同时还需要一个获取push或pull结果的方法getcolor()</p>
		<p>下面是具体子类的实现:</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class BlueState extends 
                          State{</p>
										<p>　　public void handlepush(Context c){<br />
                          　　　　 //根据push方法"如果是blue状态的切换到green" ;<br />
                          　　　　 c.setState(new GreenState());</p>
										<p>　　}<br />
                          　　public void handlepull(Context c){</p>
										<p>　　　　 //根据pull方法"如果是blue状态的切换到red" ;<br />
                          　　　　c.setState(new RedState());</p>
										<p>　　}</p>
										<p>　　public abstract void getcolor(){ return (Color.blue)}</p>
										<p>}</p>
										<p> </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>同样 其他状态的子类实现如blue一样.</p>
		<p>
				<b>第二步: 要重新改写State manager 也就是本例的Context:</b>
		</p>
		<table border="0" cellpadding="3" cellspacing="3" width="97%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">
										<p>public class Context{</p>
										<p>　　private Sate state=null; //我们将原来的 Color state 改成了新建的State 
                          state;</p>
										<p>　　//setState是用来改变state的状态 使用setState实现状态的切换<br />
                          　　pulic void setState(State state){<br /><br />
                          　　　　this.state=state;</p>
										<p>　　}</p>
										<p>　　public void push(){</p>
										<p>　　　　//状态的切换的细节部分,在本例中是颜色的变化,已经封装在子类的handlepush中实现,这里无需关心<br />
                          　　　　state.handlepush(this);<br />
                          　　　　<br />
                          　　　　//因为sample要使用state中的一个切换结果,使用getColor()<br />
                          　　　　Sample sample=new Sample(state.getColor());<br />
                          　　　　sample.operate(); </p>
										<p>　　}</p>
										<p> </p>
										<p>　　public void pull(){</p>
										<p>　　　　state.handlepull(this);<br />
                          　　　　<br />
                          　　　　Sample2 sample2=new Sample2(state.getColor());<br />
                          　　　　sample2.operate(); </p>
										<p>　　}</p>
										<p>}</p>
										<p> </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>至此,我们也就实现了State的refactorying过程.</p>
		<p>以上只是相当简单的一个实例,在实际应用中,handlepush或handelpull的处理是复杂的.</p>
		<p>状态模式优点：<br />
                    （1） 封装转换过程，也就是转换规则<br />
                    （2） 枚举可能的状态，因此，需要事先确定状态种类。<br /></p>
		<p>状态模式可以允许客户端改变状态的转换行为，而状态机则是能够自动改变状态，状态机是一个比较独立的而且复杂的机制，具体可参考一个状态机开源项目：<a href="http://sourceforge.net/projects/smframework/" target="_blank">http://sourceforge.net/projects/smframework/</a></p>
		<p>状态模式在工作流或游戏等各种系统中有大量使用，甚至是这些系统的核心功能设计，例如政府OA中，一个批文的状态有多种：未办；正在办理；正在批示；正在审核；已经完成等各种状态，使用状态机可以封装这个状态的变化规则，从而达到扩充状态时，不必涉及到状态的使用者。</p>
		<p>在网络游戏中，一个游戏活动存在开始；开玩；正在玩；输赢等各种状态，使用状态模式就可以实现游戏状态的总控，而游戏状态决定了游戏的各个方面，使用状态模式可以对整个游戏架构功能实现起到决定的主导作用。</p>
		<p>
				<strong>状态模式实质</strong>：<br />
                    使用状态模式前，客户端外界需要介入改变状态，而状态改变的实现是琐碎或复杂的。</p>
		<p>使用状态模式后，客户端外界可以直接使用事件Event实现，根本不必关心该事件导致如何状态变化，这些是由状态机等内部实现。</p>
		<p>这是一种Event-condition-State，状态模式封装了condition-State部分。</p>
		<p>每个状态形成一个子类，每个状态只关心它的下一个可能状态，从而无形中形成了状态转换的规则。如果新的状态加入，只涉及它的前一个状态修改和定义。</p>
		<p>状态转换有几个方法实现：一个在每个状态实现next()，指定下一个状态；还有一种方法，设定一个StateOwner，在StateOwner设定stateEnter状态进入和stateExit状态退出行为。</p>
		<p>状态从一个方面说明了流程，流程是随时间而改变，状态是截取流程某个时间片。</p>
		<p>
				<br />
                    相关文章：</p>
		<p>
				<a href="http://www.jdon.com/jive/article.jsp?forum=91&amp;thread=10981" target="_blank">从工作流状态机实践中总结状态模式使用心得</a>
				<br />
		</p>
		<p>参考资源:<br /><a href="http://www.research.umbc.edu/%7Etarr/cs491/lectures/StateStrategy.pdf" target="_blank">the 
                    State and Stategy</a><br /><a href="http://www.javaworld.com/javaworld/jw-08-1997/jw-08-stated.html" target="_blank">How 
                    to implement state-dependent behavior</a><br /><a href="http://www.patterndepot.com/put/8/state.pdf" target="_blank">The 
                    state patterns</a></p>
		<p> </p>
<img src ="http://www.blogjava.net/alex/aggbug/68671.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-09 10:42 <a href="http://www.blogjava.net/alex/archive/2006/09/09/68671.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之复合模式 -------.Net中的设计模式——Composite模式</title><link>http://www.blogjava.net/alex/archive/2006/09/09/68634.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Fri, 08 Sep 2006 16:51:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/09/68634.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68634.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/09/68634.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68634.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68634.html</trackback:ping><description><![CDATA[
		<div class="storycontent">
				<p>转自 <br /></p>
				<h3 class="storytitle">
						<a href="http://www.brucezhang.com/?p=57" rel="bookmark">.Net中的设计模式——Composite模式</a>
				</h3>
				<i>前言：google到一篇关于复合模式的文章，虽然是关于 .NET的，但是对于开发java同样有借鉴意义.<br /></i>
				<br />
				<p>一、模式概述</p>
				<p>描述Composite模式的最佳方式莫过于树形图。从抽象类或接口为根节点开始，然后生枝发芽，以形成树枝节点和叶结点。因此，
Composite模式通常用来描述部分与整体之间的关系，而通过根节点对该结构的抽象，使得客户端可以将单元素节点与复合元素节点作为相同的对象来看
待。</p>
				<p>由于Composite模式模糊了单元素和复合元素的区别，就使得我们为这些元素提供相关的操作时，可以有一个统一的接口。例如，我们要编写一个字
处理软件，该软件能够处理文字，对文章进行排版、预览、打印等功能。那么，这个工具需要处理的对象，就应该包括单个的文字、以及由文字组成的段落，乃至整
篇文档。这些对象从软件处理的角度来看，对外的接口应该是一致的，例如改变文字的字体，改变文字的位置使其居中或者右对齐，也可以显示对象的内容，或者打
印。而从内部实现来看，我们对段落或者文档进行操作，实质上也是对文字进行操作。从结构来看，段落包含了文字，文档又包含了段落，是一个典型的树形结构。
而其根节点正是我们可以抽象出来暴露在外的统一接口，例如接口IElement：</p>
				<p align="center">
						<img alt="composite1.GIF" src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/patterns/composite1.GIF" border="0" height="129" width="181" />
				</p>
				<p>既然文字、段落、文档都具有这些操作，因此它们都可以实现IElement接口：</p>
				<p align="center">
						<img src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/patterns/composite2.GIF" border="0" height="356" width="603" />
				</p>
				<p>从上图可以看到，对象Word、Paragraph、Document均实现了IElement接口，但Paragraph和Document与
Word对象不同的是，这两者处除了实现了IElement接口，它们还与IElement接口对象之间具有聚合的关系，且是一对多。也就是说
Paragraph与Document对象内可以包含0个到多个IElement对象，这也是与前面对字处理软件分析获得的结果是一致的。</p>
				<p>从整个结构来看，完全符合树形结构的各个要素，接口IElement是根节点，而Paragraph和Document类为枝节点，Word对象为
叶节点。既然作为枝节点，它就具有带叶节点的能力，从上图的聚合关系中我们体现出了这一点。也就是说，Paragraph和Document类除了具有排
版、打印方面的职责外，还能够添加、删除叶节点的操作。那么这些操作应该放在哪里呢？</p>
				<p>
						<font color="#0000ff">管理对子节点的管理，Composite模式提供了两种方式：一个是透明方式</font>，也就是说在根节点中声明所有用来管理子元素的方法，包括Add()、
Remove()等方法。这样一来，实现根节点接口的子节点同时也具备了管理子元素的能力。这种实现策略，最大的好处就是完全消除了叶节点和枝节点对象在
抽象层次的区别，它们具备完全一致的接口。而缺点则是不够安全。由于叶节点本身不具备管理子元素的能力，因此提供的Add()、Remove()方法在实
现层次是无意义的。但客户端调用时，却看不到这一点，从而导致在运行期间有出错的可能。</p>
				<p>
						<font color="#0000ff">另一种策略则是安全方式</font>。与透明方式刚好相反，<font color="#0000ff">它只在枝节点对象里声明管理子元素的方法</font>，<font color="#0000ff">由于叶节点不具备这些方法，当客户端在操作叶节点时，就不会出现前一种方式的安全错误</font>。然而，这种实现方式，却导致了叶节点和枝节点接口的不完全一致，这给客户端操作时带来了不便。</p>
				<p>这两种方式各有优缺点，我们在实现时，应根据具体的情况，作出更加合理的抉择。在字处理软件一例中，我选择了安全方式来实现，因为对于客户端而言，
在调用IElement接口时，通常是将其视为可被排版、打印等操作的对象。至于为Paragraph和Document对象添加、删除子对象，往往是一
种初始化的行为，完全可以放到一个单独的模块中。根据单一职责原则（SRP），我们没有必要让IElement接口负累太重。所以，我们需要对上图作稍许
的修改，在Paragraph和Document对象中增加Add()和Remove()方法：</p>
				<p align="center">
						<img src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/patterns/composite3.GIF" border="0" height="184" width="425" />
				</p>
				<p>以下是IElement对象结构的实现代码：<br />
public interface IElement<br />
{<br />
      void ChangeFont(Font font);<br />
      void Show();<br />
      //其他方法略;<br />
}<br />
public class Word<br />
{<br />
 public void ChangeFont(Font font)<br />
 {<br />
      this.font = font;<br />
 }<br />
 public void Show()<br />
 {<br />
      Console.WriteLine(this.ToString());<br />
 }<br />
 //其他方法略;<br />
}<br />
public class Paragraph<br />
{<br />
 private ArrayList elements = new ArrayList();<br />
 public void Add(IElement element)<br />
 {<br />
      elements.Add(element);<br />
 }<br />
 public void Remove(IElement element)<br />
 {<br />
      elements.Remove(element);<br />
 }<br />
 public void ChangeFont(Font font)<br />
 {<br />
      foreach (IElement element in elements)<br />
      {<br />
          element.ChangeFont(font);<br />
  }<br />
 }<br />
 public void Show()<br />
 {<br />
      foreach (IElement element in elements)<br />
      {<br />
          element.Show(font);<br />
  }<br />
 }<br />
 //其他方法略;<br />
}<br />
//Document类略；</p>
				<p>
						<font color="#ff0000">实际上，我们在为叶节点实现Add()，Remove()方法时，还需要考虑一些异常情况。例如在Paragraph类中，添加的子元素就不能是
Document对象和Paragraph对象。所以在添加IElement对象时，还需要做一些条件判断，以确定添加行为是否正确，如果错误，应抛出异
常。</font>
				</p>
				<p>采用Composite模式，我们将Word、Paragraph、Document抽象为IElement接口。虽然各自内部的实现并不相同，枝
节点和叶节点的实质也不一样，但对于调用者而言，是没有区别的。例如在类WordProcessor中，包含一个GetSelectedElement
()静态方法，它能够获得当前选择的对象：<br />
public class WordProcessor<br />
{<br />
 public static IElement GetSelectedElement(){……}<br />
}</p>
				<p>对于字处理软件的UI来说，如果要改变选中对象的字体，则可以在命令按钮cmdChangeFont的Click事件中写下如下代码：<br />
public void cmdChangeFont_Click(object sender, EventArgs e)<br />
{<br />
    WordProcessor.GetSelectedElement().ChangeFont(currentFont);<br />
}</p>
				<p>不管当前选中的对象是文字、段落还是整篇文档，对于UI而言，操作都是完全一致的，根本不需要去判断对象的类别。因此，如果在Business
Layer的类库设计时，采用Composite模式，将极大地简化UI表示层的开发工作。此外，应用该模式也较好的支持项目的可扩展性。例如，我们为
IElement接口增加了Sentence类，对于前面的例子而言，只需要修改GetSelectedElement()方法，而
cmdChangeFont命令按钮的Click事件以及Business
Layer类库原有的设计，都不需要做任何改变。这也符合OO的开放-封闭原则（OCP），即对于扩展是开放的(Open for
extension)，对于更改则是封闭的（Closed for modification）。</p>
				<p>二、.Net Framework中的Composite模式</p>
				<p>在.Net中，最能体现Composite模式的莫过于Windows或Web的控件。在这些控件中，有的包含子控件，有的则不包含且不能包含子控
件，这正好符合叶节点和枝节点的含义。所有Web控件的基类为System.Web.UI.Contril类（如果是Windows控件，则基类为
System.Windows.Forms.Control类）。其子类包含有HtmlControl、HtmlContainerControl等。按
照Composite模式的结构，枝节点和叶节点属于根节点的不同分支，同时枝节点与根节点之间应具备一个聚合关系，可以通过Add()、Remove
()方法添加和移除其子节点。设定HtmlControl为叶节点，而HtmlContaiinerControl为枝节点，那么采用透明方式的设计方
法，在.Net中控件类的结构，就应该如下图所示：</p>
				<p align="center">
						<img src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/patterns/composite4.GIF" border="0" height="255" width="353" />
				</p>
				<p>虽然根据透明方式的Composite模式，HtmlControl类与其父类Control之间也应具备一个聚合关系，但实质上该类并不具备管理
子控件的职责，因此我在类图中忽略了这个关系。此时，HtmlControl类中的Add()、Remove()方法，应该为空，或者抛出一个客户端能够
捕获的异常。</p>
				<p>然而，从具体实现来考虑，由于HtmlControl类和HtmlContainerControl类在实现细节层次，区别仅在于前者不支持子控
件，但从控件本身的功能来看，很多行为是相同或者相近的。例如HtmlControl类的Render()方法，调用了方法RenderBeginTag
()方法：<br />
protected override void Render(HtmlTextWriter writer)<br />
{<br />
      this.RenderBeginTag(writer);<br />
}<br />
protected virtual void RenderBeginTag(HtmlTextWriter writer)<br />
{<br />
      writer.WriteBeginTag(this.TagName);<br />
      this.RenderAttributes(writer);<br />
      writer.Write(’&gt;');<br />
}</p>
				<p>而HtmlContainerControl类也具有Render()方法，在这个方法中也调用了RenderBeginTag()方法，且RenderBeginTag方法的实现和前者完全一致：<br />
protected override void Render(HtmlTextWriter writer)<br />
{<br />
      this.RenderBeginTag(writer);<br />
      this.RenderChildren(writer);<br />
      this.RenderEndTag(writer);<br />
}</p>
				<p>按照上面的结构，由于HtmlControl和HtmlContainerControl之间并无继承关系，这就要求两个类中，都要重复实现
RenderBeginTag()方法，从而导致产生重复代码。根据OO的特点，解决的办法，就是让HtmlContainerControl继承自
HtmlControl类（因为HtmlContainerControl的接口比HtmlControl宽，所以只能令
HtmlContainerControl作为子类），并让RenderBeginTag()方法成为HtmlControl类的protected方
法，子类HtmlContainerControl可以直接调用这个方法。然而与之矛盾的是，HtmlContainerControl却是一个可以包含
子控件的枝节点，而HtmlControl则是不能包含子控件的叶节点，那么这样的继承关系还成立吗？</p>
				<p align="center">
						<img src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/patterns/composite5.GIF" border="0" height="361" width="271" />
				</p>
				<p>HtmlControl类对Add()方法和Remove()方法的重写后，这两个方法内容为空。由于HtmlContainerControl类
继承HtmlControl类，但我们又要求它的Add()和Remove()方法和Control类保持一致，而父类HtmlControl已经重写这
两个方法，此时是无法直接继承来自父类的方法的。以上是采用透明方式的设计。</p>
				<p>如果采用安全方式，仍然有问题。虽然在HtmlControl类中不再有Add()和Remove()方法，但由于Control类和
HtmlContainerControl类都允许添加子控件，它们包含的Add()、Remove()方法，只能分别实现。这样的设计必然会导致重复代
码。这也是与我们的期望不符的。</p>
				<p>那么在.Net中，Control类究竟是怎样实现的呢？下面，我将根据.Net实现Control控件的源代码，来分析Control控件的真实结构，以及其具体的实现细节。</p>
				<p>三、深入分析.Net中的Composite模式</p>
				<p>首先，我们来剖析Web控件的基类Control类的内部实现：</p>
				<p>public class Control : IComponent, IDisposable, IParserAccessor, IDataBindingsAccessor<br />
{<br />
       // Events;略  <br />
       // Methods<br />
 public Control()<br />
 {<br />
             if (this is INamingContainer)<br />
             {<br />
                    this.flags[0×80] = true;<br />
             }<br />
 }<br />
 public virtual bool HasControls()<br />
 {<br />
              if (this._controls != null)<br />
              {<br />
                    return (this._controls.Count &gt; 0);<br />
              }<br />
              return false;<br />
 }<br />
 public virtual void DataBind()<br />
        {<br />
              this.OnDataBinding(EventArgs.Empty);   <br />
              if (this._controls != null)           <br />
       {                <br />
              string text1 = this._controls.SetCollectionReadOnly(”Parent_collections_readonly”);<br />
                        int num1 = this._controls.Count;<br />
                 for (int num2 = 0; num2 &lt; num1; num2++)                 <br />
   {<br />
                         this._controls[num2].DataBind();<br />
                   }<br />
                   this._controls.SetCollectionReadOnly(text1);<br />
              }<br />
 }<br />
        protected virtual void Render(HtmlTextWriter writer)<br />
 {<br />
              this.RenderChildren(writer);<br />
 }<br />
 protected virtual ControlCollection CreateControlCollection()<br />
 {<br />
              return new ControlCollection(this);<br />
 }<br />
       // Properties<br />
 public virtual ControlCollection Controls<br />
 {<br />
             get<br />
             {<br />
                   if (this._controls == null)<br />
                   {<br />
                         this._controls = this.CreateControlCollection();<br />
                   }<br />
                   return this._controls;<br />
             }<br />
 }<br />
        // Fields<br />
        private ControlCollection _controls;<br />
}</p>
				<p>Control基类中的属性和方法很多，为清晰起见，我只保留了几个与模式有关的关键方法与属性。在上述的源代码中，我们需要注意几点：</p>
				<p>1、Control类不是抽象类，而是具体类。这是因为在设计时，我们可能会创建Control类型的实例。根据这一点来看，这并不符合OOP的要
求。一般而言，作为抽象出来的基类，必须定义为接口或抽象类。不过在实际的设计中，也不应拘泥于这些条条框框，而应审时度势，根据实际的情况来抉择最佳的
设计方案。<br />
2、公共属性Controls为ControlCollection类型，且该属性为virtual属性。也就是说，这个属性可以被它的子类
override。同时，该属性为只读属性，在其get访问器中，调用了方法CreateControlCollection()；这个方法为
protected虚方法，默认的实现是返回一个ControlCollection实例。<br />
3、方法HasControls()，功能为判断Control对象是否有子控件。它判断的依据是根据私有字段_controls（即公共属性
Controls）的Count值。但是需要注意的是，通过HasControls()方法的返回值，并不能决定对象本身属于叶节点，还是枝节点。因为即
使是枝节点其内部仍然可以不包含任何子对象。<br />
4、
方法DataBind()的实现中，首先调用了自身的OnDataBinding()方法，然后又遍历了Controls中的所有控件，并调用其
DataBind()方法。该方法属于控件的共有行为，从这里可以看出不管是作为叶节点的控件，还是作为枝节点的控件，它们都实现统一的接口。对于客户端
调用而言，枝节点和叶节点是没有区别的。<br />
5、 Control类的完整源代码中，并不存在Add()、Remove()等类似的方法，以提供添加和移除子控件的功能。事实上，继承Control类的所有子类均不存在Add()、Remove()等方法。</p>
				<p>显然，在Control类的定义和实现中，值得我们重视的是公共属性Controls的类型ControlCollection。顾名思义，该类必
然是一个集合类型。是否有关子控件的操作，都是在ControlCollection类型中实现呢？我们来分析一下ControlCollection的
代码：<br />
public class ControlCollection : ICollection, IEnumerable<br />
{<br />
       // Methods<br />
 public ControlCollection(Control owner)<br />
 {<br />
               this._readOnlyErrorMsg = null;<br />
               if (owner == null)<br />
               {<br />
                       throw new ArgumentNullException("owner");<br />
               }<br />
               this._owner = owner;<br />
        }<br />
 public virtual void Add(Control child)<br />
        {<br />
               if (child == null)<br />
               {<br />
                throw new ArgumentNullException("child");<br />
               }<br />
               if (this._readOnlyErrorMsg != null)<br />
                   {<br />
                throw new HttpException(HttpRuntime.FormatResourceString(this._readOnlyErrorMsg));<br />
               }<br />
               if (this._controls == null)<br />
               {<br />
                   this._controls = new Control[5];<br />
               }<br />
               else if (this._size &gt;= this._controls.Length)<br />
               {<br />
                   Control[] controlArray1 = new Control[this._controls.Length * 4];<br />
                   Array.Copy(this._controls, controlArray1, this._controls.Length);<br />
                   this._controls = controlArray1;<br />
               }<br />
               int num1 = this._size;<br />
               this._controls[num1] = child;<br />
               this._size++;<br />
               this._version++;<br />
               this._owner.AddedControl(child, num1);<br />
        }<br />
        public virtual void Remove(Control value)<br />
 {<br />
               int num1 = this.IndexOf(value);<br />
               if (num1 &gt;= 0)<br />
               {<br />
                this.RemoveAt(num1);<br />
               }<br />
        }<br />
        // Indexer<br />
 public virtual Control this[int index]<br />
 {<br />
               get<br />
               {<br />
                    if ((index &lt; 0) || (index &gt;= this._size))<br />
                    {<br />
                         throw new ArgumentOutOfRangeException(”index”);<br />
                    }<br />
                    return this._controls[index];<br />
               }<br />
 }<br />
 // Properties    <br />
 public int Count<br />
 {<br />
        get<br />
               {<br />
                    return this._size;<br />
               }<br />
        }<br />
 protected Control Owner<br />
 {<br />
               get<br />
               {<br />
                    return this._owner;<br />
               }<br />
 }<br />
        protected Control Owner { get; }   <br />
        // Fields<br />
        private Control[] _controls;<br />
        private const int _defaultCapacity = 5;<br />
        private const int _growthFactor = 4;<br />
 private Control _owner;    <br />
}</p>
				<p>一目了然，正是ControlCollection的Add()、Remove()方法完成了对子控件的添加和删除。例如：<br />
Control parent = new Control();<br />
Control child = new Child();<br />
//添加子控件child;<br />
parent.Controls.Add(child);<br />
//移除子控件child;<br />
parent.Controls.Remove(child);</p>
				<p>为什么要专门提供ControlCollection类型来管理控件的子控件呢？首先，作为类库使用者，自然希望各种类型的控件具有统一的接口，尤
其是自定义控件的时候，不希望自己重复定义管理子控件的操作；那么采用透明方式自然是最佳方案。然而，在使用控件的时候，安全也是需要重点考虑的，如果不
考虑子控件管理的合法性，一旦使用错误，会导致整个应用程序出现致命错误。从这样的角度考虑，似乎又应采用安全方式。这里就存在一个抉择。故而，.Net
在实现Control类库时，利用了职责分离的原则，将控件对象管理子控件的属性与行为和控件本身分离，并交由单独的ControlCollection
类负责。同时采用聚合而非继承的方式，以一个公共属性Controls，存在于Control类中。这种方式，集保留了透明方式和安全方式的优势，又摒弃
了这两种方式固有的缺陷，因此我名其为“复合方式”。</p>
				<p>“复合方式”的设计，其对安全的保障，不仅仅是去除了Control类关于子控件管理的统一接口，同时还通过异常管理的方式，在ControlCollection类的子类中实现：<br />
public class EmptyControlCollection : ControlCollection<br />
{<br />
        // Methods<br />
 public EmptyControlCollection(Control owner) : base(owner)<br />
 {}<br />
 public override void Add(Control child)<br />
 {<br />
            this.ThrowNotSupportedException();<br />
 }                         <br />
        private void ThrowNotSupportedException()<br />
        {<br />
            throw new
HttpException(HttpRuntime.FormatResourceString(”Control_does_not_allow_children”,
base.Owner.GetType().ToString()));<br />
        }<br />
}</p>
				<p>EmptyControlCollection继承了ControlCollection类，并重写了Add()等添加子控件的方法，使其抛出一个
异常。注意，它并没有重写父类的Remove()方法，这是因为ControlCollection类在实现Remove()方法时，对集合内的数据进行
了非空判断。而在EmptyControlCollection类中，是不可能添加子控件的，直接调用父类的Remove()方法，是不会出现错误的。</p>
				<p>既然管理子控件的职责由ControlCollection类型负责，且Control类中的公共属性Controls即为
ControlCollection类型。所以，对于控件而言，如果是树形结构中的叶节点，它不能包含子控件，它的Controls属性就应为
EmptyControlCollection类型，假如用户调用了Controls的Add()方法，就会抛出异常。如果控件是树形结构中的枝节点，它
支持子控件，那么Controls属性就是ControlCollection类型。究竟是枝节点还是叶节点，决定权在于公共属性Controls：<br />
public virtual ControlCollection Controls<br />
{<br />
      get<br />
      {<br />
             if (this._controls == null)<br />
             {<br />
                   this._controls = this.CreateControlCollection();<br />
             }<br />
             return this._controls;<br />
      }<br />
}</p>
				<p>在属性的get访问器中，调用了protected方法CreateControlCollection()，它创建并返回了一个ControlCollection实例：<br />
protected virtual ControlCollection CreateControlCollection()<br />
{<br />
     return new ControlCollection(this);<br />
}</p>
				<p>很明显，在Control基类实现Controls属性时，采用了Template Method模式,它推迟了ControlCollection的创建，将决定权交给了CreateControlCollection()方法。</p>
				<p>如果我们需要定义一个控件，要求它不能管理子控件，就重写CreateControlCollection()方法，返回EmptyControlCollection对象：</p>
				<p>protected override ControlCollection CreateControlCollection()<br />
{<br />
     return new EmptyControlCollection(this);<br />
}<br />
 <br />
现在再回过头来看HtmlControl和HtmlContainerControl类。根据前面的分析，我们要求
HtmlContainerControl继承HtmlControl类，同时，HtmlContainerControl应为枝节点，能够管理子控件；
HtmlControl则为叶节点，不支持子控件。通过引入ControlCollection类和其子类
EmptyControlCollection，以及Template Method模式后，这些类之间的关系与结构如下所示：</p>
				<p align="center">
						<img src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/patterns/composite6.GIF" border="0" height="380" width="661" />
				</p>
				<p>HtmlContainerControl继承了HtmlControl类，这两个类都重写了自己父类的protected方法
CreateControlCollection()。HtmlControl类，该方法返回EmptyControlCollection对象，使其成
为了不包含子控件的叶节点；HtmlContainerControl类中，该方法则返回ControlCollection对象，从而被赋予了管理子控
件的能力，成为了枝节点：<br />
public abstract class HtmlControl : Control, IAttributeAccessor<br />
{<br />
        // Methods<br />
 protected override ControlCollection CreateControlCollection()<br />
 {<br />
            return new EmptyControlCollection(this);<br />
 }<br />
}<br />
public abstract class HtmlContainerControl : HtmlControl<br />
{<br />
       // Methods<br />
 protected override ControlCollection CreateControlCollection()<br />
 {<br />
            return new ControlCollection(this);<br />
 }<br />
}</p>
				<p>HtmlControl和HtmlContainerControl类均为抽象类。要定义它们的子类，如果不重写其父类的
CreateControlCollection()方法，那么它们的Controls属性，就与父类完全一致。例如HtmlImage控件继承自
HtmlControl类，该控件不能添加子控件；而HtmlForm控件则继承自HtmlContainerControl类，显然，HtmlForm
控件是支持添加子控件的操作的。</p>
				<p>.Net的控件设计采用Composite模式的“复合方式”，较好地将控件的透明性与安全性结合起来，它的特点是：</p>
				<p>1、在统一接口中消除了Add()、Remove()等子控件的管理方法，而由ControlCollection类实现，同时通过EmptyControlCollection类保障了控件进一步的安全；<br />
2、控件能否管理子控件，不由继承的层次决定；而是通过重写CreateControlCollection()方法，由Controls属性的真正类型来决定。</p>
				<p>如此一来，要定义自己的控件就更加容易。我们可以任意地扩展自己的控件类。不管继承自Control，还是HtmlControl或
HtmlContainerControl，都可以轻松地定义出具有枝节点或叶节点属性的新控件。如果有新的需求要求改变管理子控件的方式，我们还可以定
义继承自ControlCollection的类，并在控件类的方法CreateControlCollection()中创建并返回它的实例。
</p>
		</div>
<img src ="http://www.blogjava.net/alex/aggbug/68634.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-09 00:51 <a href="http://www.blogjava.net/alex/archive/2006/09/09/68634.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之复合模式（from jdon）</title><link>http://www.blogjava.net/alex/archive/2006/09/09/68631.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Fri, 08 Sep 2006 16:44:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/09/68631.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68631.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/09/68631.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68631.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68631.html</trackback:ping><description><![CDATA[
		<div class="postbody">
				<h3 align="center">设计模式之Composite(组合)</h3>
				<p align="center">
						<a href="http://www.jdon.com/aboutme.htm">
								<font color="#002c99">板桥里人</font>
						</a> http://www.jdon.com 2002/04/27（转载请保留）</p>
				<p align="center">
						<a href="http://www.jdon.com/mybook/index.htm" target="_blank">
								<strong>
								</strong>
						</a> </p>
				<p>
						<b>Composite模式定义</b>:<br />将对象以树形结构组织起来,以达成“部分－整体” 的层次结构，使得客户端对单个对象和组合对象的使用具有一致性.</p>
				<p>Composite比较容易理解，<font color="#0000ff">想到Composite就应该想到树形结构图</font>。组合体内这些对象都有共同接口,<font color="#0000ff">当组合体一个对象的方法被调用执行
时，Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行。可以用牵一动百来形容。</font></p>
				<p>
						<b>所以Composite模式使用到Iterator模式</b>，和Chain of Responsibility模式类似。</p>
				<p>
						<b>Composite好处</b>:<br />1.使客户端调用简单，客户端可以一致的使用组合结构或其中单个对象，用户就不必关系自己处理的是单个对象还是整个组合结构，这就简化了客户端代码。<br />2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。</p>
				<p>
						<b>如何使用Composite?</b>
						<br />首先定义一个接口或抽象类，这是设计模式通用方式了，其他设计模式对接口内部定义限制不多，<font color="#ff1493">Composite却有个规定，那就是要在接口内部定义一个用于访问和管理Composite组合体的对象们（或称部件Component）.</font></p>
				<p>下面的代码是以抽象类定义，一般尽量用接口interface,</p>
				<table border="0" cellpadding="3" cellspacing="3" width="80%">
						<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 border="0" cellpadding="3" cellspacing="3" width="80%">
						<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 /><i>还有一种可能是，一个部件也是一个组合体，就是说这个部件下面还有'儿子'，这是树形结构中通常的情况</i>，应该比较容易理解。现在我们先要定义这个组合体：</p>
				<table border="0" cellpadding="3" cellspacing="3" width="80%">
						<tbody>
								<tr>
										<td bgcolor="#cccccc">
												<p>abstract class CompositeEquipment extends Equipment<br />{<br />　　private int i=0; <br />　　//定义一个Vector 用来存放'儿子'<br />　　<font color="#ff1493">private Lsit equipment=new ArrayList();</font><br /><br />　　public CompositeEquipment(String name) { super(name); }<br /><br />　　<font color="#0000ff">public boolean add(Equipment equipment) { <br />　　　　 this.equipment.add(equipment); <br />　　　　 return true; <br />　　 }</font><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>　　<font color="#ff1493">//注意这里，这里就提供用于访问自己组合体内的部件方法。<br />　　//上面dIsk 之所以没有，是因为Disk是个单独(Primitive)的元素.</font><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 border="0" cellpadding="3" cellspacing="3" width="80%">
						<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是个很巧妙体现智慧的模式，<font color="#0000ff">在实际应用中，如果碰到树形结构，我们就可以尝试是否可以使用这个模式。</font></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 border="0" cellpadding="3" cellspacing="3" width="80%">
						<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>
				<p>:)</p>
		</div>
<img src ="http://www.blogjava.net/alex/aggbug/68631.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-09 00:44 <a href="http://www.blogjava.net/alex/archive/2006/09/09/68631.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之复合模式</title><link>http://www.blogjava.net/alex/archive/2006/09/08/68627.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Fri, 08 Sep 2006 15:59:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/08/68627.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68627.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/08/68627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68627.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68627.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自: CCIENET		自从J2EE出现以来，就大大简化了在Java下的企业级开发。但是随着J2EE越来越普遍地被应用到各个领域中，开发者们渐渐意识到需要一种方法来标准化应用程序的开发过程，他们采用的方法是标准化应用程序的结构层。在结构层通常封装了一些独立于业务逻辑的复杂技术，以便在业务逻辑和底层的架构之间建立起弱连接。无可否认，J2EE是一个很成功的技术，它为一些基本的任务提供了一...&nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2006/09/08/68627.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/68627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-08 23:59 <a href="http://www.blogjava.net/alex/archive/2006/09/08/68627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Java设计模式之外观模式研究</title><link>http://www.blogjava.net/alex/archive/2006/09/03/67333.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sat, 02 Sep 2006 16:07:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/03/67333.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/67333.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/03/67333.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/67333.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/67333.html</trackback:ping><description><![CDATA[外观模式（Facade pattern）涉及到子系统的一些类。所谓子系统，是为提供一系列相关的特征（功能）而紧密关联的一组类。例如，一个Account类、Address类和CreditCard类相互关联，成为子系统的一部分，提供在线客户的特征。<br /><br />　
　在真实的应用系统中，一个子系统可能由很多类组成。子系统的客户为了它们的需要，需要和子系统中的一些类进行交互。客户和子系统的类进行直接的交互会导
致客户端对象和子系统（Figure1）之间高度耦合。任何的类似于对子系统中类的接口的修改，会对依赖于它的所有的客户类造成影响。<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"> <img src="http://dev.yesky.com/imagelist/05/11/8k4m329893mg.bmp" /> <br />Figure1: <a href="http://www.yesky.com/key/1880/161880.html" class="bluekey" target="_blank">Client</a> Interaction with Subsystem Classes before Applying the Facade Pattern </div></td></tr></tbody></table><br />　　外观模式（Facade pattern）很适用于在上述情况。外观模式（Facade pattern）为子系统提供了一个更高层次、更简单的接口，从而降低了子系统的复杂度和依赖。这使得子系统更易于使用和管理。<br /><br />　　外观是一个能为子系统和客户提供简单接口的类。当正确的应用外观，客户不再直接和子系统中的类交互，而是与外观交互。外观承担与子系统中类交互的责任。实际上，外观是子系统与客户的接口，这样外观模式降低了子系统和客户的耦合度(Figure2). <br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"> <img src="http://dev.yesky.com/imagelist/05/11/54hkko9rj4a6.bmp" /> <br />Figure2: Client Interaction with Subsystem Classes after Applying the Facade Pattern </div></td></tr></tbody></table><br />　　从Figure2中我们可以看到：外观对象隔离了客户和子系统对象，从而降低了耦合度。当子系统中的类进行改变时，客户端不会像以前一样受到影响。<br /><br />　　尽管客户使用由外观提供的简单接口，但是当需要的时候，客户端还是可以视外观不存在，直接访问子系统中的底层次的接口。这种情况下，它们之间的依赖/耦合度和原来一样。 <br /><br />　　例子：<br /><br />　　让我们建立一个应用：<br /><br />　　（1） 接受客户的详细资料（账户、地址和信用卡信息）<br /><br />　　（2） 验证输入的信息<br /><br />　　（3） 保存输入的信息到相应的文件中。<br /><br />　　这个应用有三个类：Account、Address和CreditCard。每一个类都有自己的验证和保存数据的方法。<br /><br />　　Listing1: AccountClass <br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>public class Account { <br />　String firstName; <br />　String lastName; <br />　final String ACCOUNT_DATA_FILE = "AccountData.txt"; <br />　public Account(String fname, String lname) { <br />　　firstName = fname; <br />　　lastName = lname; <br />　} <br />　public boolean isValid() { <br />　　/* <br />　　Let's go with simpler validation <br />　　here to keep the example simpler. <br />　　*/ <br />　　… <br />　　… <br />　} <br />　public boolean save() { <br />　　FileUtil futil = new FileUtil(); <br />　　String dataLine = getLastName() + ”," + getFirstName(); <br />　　return futil.writeToFile(ACCOUNT_DATA_FILE, dataLine,true, true); <br />　} <br />　public String getFirstName() { <br />　　return firstName; <br />　} <br />　public String getLastName() { <br />　　return lastName; <br />　} <br />} </td></tr></tbody></table><br />　　Listing2: Address Class <br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>public class Address { <br />　String address; <br />　String city; <br />　String state; <br />　final String ADDRESS_DATA_FILE = "Address.txt"; <br />　public Address(String add, String cty, String st) { <br />　　address = add; <br />　　city = cty; <br />　　state = st; <br />　} <br />　public boolean isValid() { <br />　　/* <br />　　The address validation algorithm <br />　　could be complex in <a href="http://www.yesky.com/key/4733/164733.html" class="bluekey" target="_blank">real</a>-world <br />　　applications. <br />　　Let's go with simpler validation <br />　　here to keep the example simpler. <br />　　*/ <br />　　if (getState().<a href="http://www.yesky.com/key/914/160914.html" class="bluekey" target="_blank">trim</a>().length() &lt; 2) <br />　　　return false; <br />　　return true; <br />　} <br />　public boolean save() { <br />　　FileUtil futil = new FileUtil(); <br />　　String dataLine = getAddress() + ”," + getCity() + ”," + getState(); <br />　　return futil.writeToFile(ADDRESS_DATA_FILE, dataLine,true, true); <br />　} <br />　public String getAddress() { <br />　　return address; <br />　} <br />　public String getCity() { <br />　　return city; <br />　} <br />　public String getState() { <br />　　return state; <br />　} <br />} </td></tr></tbody></table><br />　　Listing3: CreditCard Class <br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>public class CreditCard { <br />　String cardType; <br />　String cardNumber; <br />　String cardExpDate; <br />　final String CC_DATA_FILE = "CC.txt"; <br />　public CreditCard(String ccType, String ccNumber, <br />　String ccExpDate) { <br />　　cardType = ccType; <br />　　cardNumber = ccNumber; <br />　　cardExpDate = ccExpDate; <br />　} <br />　public boolean isValid() { <br />　　/* <br />　　Let's go with simpler validation <br />　　here to keep the example simpler. <br />　　*/ <br />　　if (getCardType().equals(AccountManager.VISA)) { <br />　　　return (getCardNumber().trim().length() == 16); <br />　　} <br />　　if (getCardType().equals(AccountManager.<a href="http://www.yesky.com/key/81/160081.html" class="bluekey" target="_blank">DISCOVER</a>)) { <br />　　　return (getCardNumber().trim().length() == 15); <br />　　} <br />　　if (getCardType().equals(AccountManager.<a href="http://www.yesky.com/key/2407/162407.html" class="bluekey" target="_blank">MASTER</a>)) { <br />　　　return (getCardNumber().trim().length() == 16); <br />　　} <br />　　return false; <br />　} <br />　public boolean save() { <br />　　FileUtil futil = new FileUtil(); <br />　　String dataLine = getCardType() + ,”" + getCardNumber() + ”," + getCardExpDate(); <br />　　return futil.writeToFile(CC_DATA_FILE, dataLine, true, true); <br />　} <br />　public String getCardType() { <br />　　return cardType; <br />　} <br />　public String getCardNumber() { <br />　　return cardNumber; <br />　} <br />　public String getCardExpDate() { <br />　　return cardExpDate; <br />　} <br />} </td></tr></tbody></table><br /><div align="center"><img src="http://dev.yesky.com/imagelist/05/11/ge36sg91s750.bmp" />  <br />Figure3: Subsystem Classes to Provide the Necessary Functionality to Validate and Save the Customer Data<br /><br /><br /><br /><div align="left">让我们建立一个客户AccountManager，它提供用户输入数据的用户界面。<br /><br />　　Listing4: Client AccountManager Class <br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>public class AccountManager extends JFrame { <br />　public static final String newline = "\n"; <br />　public static final String VALIDATE_SAVE = "Validate &amp; Save"; <br />　… <br />　… <br />　public AccountManager() { <br />　　super(" Facade Pattern - Example "); <br />　　cmbCardType = new JComboBox(); <br />　　cmbCardType.addItem(AccountManager.VISA); <br />　　cmbCardType.addItem(AccountManager.MASTER); <br />　　cmbCardType.addItem(AccountManager.DISCOVER); <br />　　… <br />　　… <br />　　//Create buttons <br />　　JButton validateSaveButton = new JButton(AccountManager.VALIDATE_SAVE); <br />　　… <br />　　… <br />　} <br />　public String getFirstName() { <br />　　return txtFirstName.getText(); <br />　} <br />　… <br />　… <br />}//End of class AccountManager </td></tr></tbody></table><br />　　当客户AccountManage运行的时候，展示的用户接口如下：<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://dev.yesky.com/imagelist/05/11/twnzl54814vm.bmp" />  <br />Figure4: User Interface to Enter the Customer Data </div></td></tr></tbody></table><br />　　为了验证和保存输入的数据，客户AccountManager需要：<br /><br />　　（1） 建立Account、Address和CreditCard对象。 <br /><br />　　（2） 用这些对象验证输入的数据<br /><br />　　（3） 用这些对象保存输入的数据。<br /><br />　　下面是对象间的交互顺序图：<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://dev.yesky.com/imagelist/05/11/zho86r3qh3wc.bmp" /> <br />Figure5: How a Client Would Normally Interact (Directly) with Subsystem Classes to Validate and Save the Customer Data </div></td></tr></tbody></table><br />　
　在这个例子中应用外观模式是一个很好的设计，它可以降低客户和子系统组件（Address、Account和CreditCard）之间的耦合度。应用
外观模式，让我们定义一个外观类CustomerFacade (Figure6 and
Listing5)。它为由客户数据处理类（Address、Account和CreditCard）所组成的子系统提供一个高层次的、简单的接口。 <br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>CustomerFacade <br />address:String <br />city:String <br />state:String <br />cardType:String <br />cardNumber:String <br />cardExpDate:String <br />fname:String <br />lname:String <br />setAddress(inAddress:String) <br />setCity(inCity:String) <br />setState(inState:String) <br />setCardType(inCardType:String) <br />setCardNumber(inCardNumber:String) <br />setCardExpDate(inCardExpDate:String) <br />setFName(inFName:String) <br />setLName(inLName:String) <br />saveCustomerData()</td></tr></tbody></table><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"> <img src="http://dev.yesky.com/imagelist/05/11/ul12pq6b6o6k.bmp" /> <br />Figure6: Facade Class to Be Used by the Client in the Revised Design </div></td></tr></tbody></table><br />　　Listing5: CustomerFacade Class <br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>public class CustomerFacade { <br />　private String address; <br />　private String city; <br />　private String state; <br />　private String cardType; <br />　private String cardNumber; <br />　private String cardExpDate; <br />　private String fname; <br />　private String lname; <br />　public void setAddress(String inAddress) { <br />　　address = inAddress; <br />　} <br />　public void setCity(String inCity) { <br />　　city = inCity; <br />　} <br />　public void setState(String inState) { <br />　　state = inState; <br />　} <br />　public void setFName(String inFName) { <br />　　fname = inFName; <br />　} <br />　public void setLName(String inLName) { <br />　　lname = inLName; <br />　} <br />　public void setCardType(String inCardType) { <br />　　cardType = inCardType; <br />　} <br />　public void setCardNumber(String inCardNumber) { <br />　　cardNumber = inCardNumber; <br />　} <br />　public void setCardExpDate(String inCardExpDate) { <br />　　cardExpDate = inCardExpDate; <br />　} <br />　public boolean saveCustomerData() { <br />　　Address objAddress; <br />　　Account objAccount; <br />　　CreditCard objCreditCard; <br />　　/* <br />　　　client is transparent from the following <br />　　　set of subsystem related operations. <br />　　*/ <br />　　boolean validData = true; <br />　　String errorMessage = ""; <br />　　objAccount = new Account(fname, lname); <br />　　if (objAccount.isValid() == false) { <br />　　　validData = false; <br />　　　errorMessage = "Invalid FirstName/LastName"; <br />　　} <br />　　objAddress = new Address(address, city, state); <br />　　if (objAddress.isValid() == false) { <br />　　　validData = false; <br />　　　errorMessage = "Invalid Address/City/State"; <br />　　} <br />　　objCreditCard = new CreditCard(cardType, cardNumber, cardExpDate); <br />　　if (objCreditCard.isValid() == false) { <br />　　　validData = false; <br />　　　errorMessage = "Invalid CreditCard Info"; <br />　　} <br />　　if (!validData) { <br />　　　System.out.println(errorMessage); <br />　　　return false; <br />　　} <br />　　if (objAddress.save() &amp;&amp; objAccount.save() &amp;&amp; objCreditCard.save()) { <br />　　　return true; <br />　　} else { <br />　　　return false; <br />　　} <br />　} <br />} </td></tr></tbody></table><br />　
　CustomerFacade类以saveCustomData方法的形式提供了业务层次上的服务。客户AccountManager不是直接和子系统
的每一个组件交互，而是使用了由CustomFacade对象提供的验证和保存客户数据的更高层次、更简单的接口(Figure7).<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://dev.yesky.com/imagelist/05/11/3g0o40j70aua.bmp" /> <br />Figure7: Class Association with the Fa?ade Class in Place 。</div></td></tr></tbody></table><br />　　在新的设计中，为了验证和保存客户数据，客户需要：<br /><br />　　（1） 建立或获得外观对象CustomFacade的一个实例。<br /><br />　　（2） 传递数据给CustomFacade实例进行验证和保存。<br /><br />　　（3） 调用CustomFacade实例上的saveCustomData方法。<br /><br />　　CustomFacade处理创建子系统中必要的对象并且调用这些对象上相应的验证、保存客户数据的方法这些细节问题。客户不再需要直接访问任何的子系统中的对象。<br /><br />　　Figure8展示了新的设计的消息流图：<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://dev.yesky.com/imagelist/05/11/0i6g0li0e5us.bmp" /> <br />Figure 22.8: In the Revised Design, Clients Interact with the Fa?ade Instance to Interface with the Subsystem </div></td></tr></tbody></table><br />　　<b>重要提示</b>：<br /><br />　　下面是应用外观模式的注意事项：<br /><br />　　（1） 在设计外观时，不需要增加额外的功能。<br /><br />　　（2） 不要从外观方法中返回子系统中的组件给客户。例如：有一个下面的方法：<br /><br />　　CreditCard getCreditCard() <br /><br />　　会报漏子系统的细节给客户。应用就不能从应用外观模式中取得最大的好处。<br /><br />　　（3）应用外观的目的是提供一个高层次的接口。因此，外观方法最适合提供特定的高层次的业务服务，而不是进行底层次的单独的业务执行。</div></div><img src ="http://www.blogjava.net/alex/aggbug/67333.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-03 00:07 <a href="http://www.blogjava.net/alex/archive/2006/09/03/67333.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出Java设计模式之适配器模式</title><link>http://www.blogjava.net/alex/archive/2006/09/03/67332.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sat, 02 Sep 2006 16:02:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/03/67332.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/67332.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/03/67332.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/67332.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/67332.html</trackback:ping><description><![CDATA[
		<font color="#0000ff">小结:适配器模式用插座的适配器最为形象，插头是2口的，插座是3口的，中间的适配器就是同时支持2口和三口的。从对象的角度就是一般继承一个实现一个，总之，前方百计把两者都关联起来 。<br /><br /><br /></font>通常，客户类（clients of class）通过类的接口访问它提供的服务。有时，现有的类（existing class）可以提供客户类的功能
需要，但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口太详细或者缺乏详细或接口的名称与客户类所查找的不同等诸多不同原因导致的。<br /><br />　　在这种情况下，现有的接口需要转化（<a href="http://www.yesky.com/key/476/125476.html" class="bluekey" target="_blank">convert</a>）
为客户类期望的接口，这样保证了对现有类的重用。如果不进行这样的转化，客户类就不能利用现有类所提供的功能。适配器模式
（Adapter Pattern）可以完成这样的转化。适配器模式建议定义一个包装类，包装有不兼容接口的对象。这个包装类指的就是适配器
（Adapter），它包装的对象就是适配者(Adaptee)。适配器提供客户类需要的接口，适配器接口的实现是把客户类的请求转化为对适配者的相应接
口的调用。换句话说：当客户类调用适配器的方法时，在适配器类的内部调用适配者类的方法，这个过程对客户类是透明的，客户类并不直接访问适配者类。因此，
适配器可以使由于借口不兼容而不能交互的类可以一起工作（work together）。<br /><br />　　在上面讨论的接口：<br /><br />　　（1）    不是指在JAVA编程语言中接口的概念，虽然类的接口可以通过JAVA借扩来定义。<br /><br />　　<a href="http://www.yesky.com/key/873/140873.html" class="bluekey" target="_blank">（2）</a>    不是指由<a href="http://www.yesky.com/key/2059/137059.html" class="bluekey" target="_blank">窗体</a>和GUI控件所组成的GUI应用程序的用户接口。<br /><br />　　（3）    而是指类所报漏的，被其他类调用的编程接口，<br /><br />　　类适配器（Class Adapter）VS对象适配器(Object Adapter)<br /><br />　　适配器总体上可以分为两类??类适配器（Class Adapter）VS对象适配器(Object Adapter)<br />     
<h4>　类适配器：</h4><br />　　类适配器是通过继承类适配者类（Adaptee Class）实现的，另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候，适配器内部调用它所继承的适配者的方法。<br />     
<h4>　对象适配器：</h4>　　对象适配器包含一个适配器者的引用（<a href="http://www.yesky.com/key/1298/141298.html" class="bluekey" target="_blank">reference</a>），与类适配器相同，对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候，对象适配器调它所包含的适配器者实例的适当方法。<br /><br />　　<font color="#ff0000">下表是类适配器（Class Adapter）和对象适配器(Object Adapter)的详细不同</font>：<br /><br /><p align="center"><img src="http://dev.yesky.com/imagelist/05/10/b6z1pomi30yn.bmp" /></p>　　<br />    <br />　　例子：<br /><br />　　让我们建立一个验证给定客户地址的应用。这个应用是作为大的客户数据管理应用的一部分。<br /><br />　　让我们定义一个Customer类：<br /><br />Customer <br /><p align="center"><img src="http://dev.yesky.com/imagelist/05/10/2g903vv3404w.bmp" height="109" width="525" /></p><br /><br />Figure 20.1: Customer Class <br />Listing 20.1: Customer Class <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">class</font></b> Customer {  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">static</font></b> <b><font color="#0000ff">final</font></b> <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> US = <font color="#ff33ff">"US"</font>;  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">static</font></b> <b><font color="#0000ff">final</font></b> <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> CANADA = <font color="#ff33ff">"Canada"</font>;  
</li><li>  <b><font color="#0000ff">private</font></b> <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> address;  
</li><li>  <b><font color="#0000ff">private</font></b> <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> name;  
</li><li>  <b><font color="#0000ff">private</font></b> <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> zip, state, type;  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress() {  
</li><li>          …  
</li><li>          …  
</li><li>  }  
</li><li>  <b><font color="#0000ff">public</font></b> Customer(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_name, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>                  <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_zip, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_state,  
</li><li>                  <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_type) {  
</li><li>    name = inp_name;  
</li><li>    address = inp_address;  
</li><li>    zip = inp_zip;  
</li><li>    state = inp_state;  
</li><li>    type = inp_type;  
</li><li>  }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div>　
　不同的客户对象创建Customer对象并调用（invoke）isValidAddress方法验证客户地址的有效性。为了验证客户地址的有效性，
Customer类期望利用一个地址验证类（address validator class），这个验证类提供了在接口
AddressValidator中声明的接口。<br /><br />　　Listing 20.2: AddressValidator as an Interface <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">interface</font></b> AddressValidator {  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>     <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_zip, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_state);  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div><br />　　让我们定义一个USAddress的验证类，来验证给定的U.S地址。<br /><br />　　Listing 20.3: USAddress Class <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">class</font></b> USAddress <b><font color="#0000ff">implements</font></b> AddressValidator {  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>     <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_zip, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_state) {  
</li><li>   <b><font color="#0000ff">if</font></b> (inp_address.trim().<b><font color="#0000ff">length</font></b>() &lt; 10)  
</li><li>     <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">false</font></b>;  
</li><li>   <b><font color="#0000ff">if</font></b> (inp_zip.trim().<b><font color="#0000ff">length</font></b>() &lt; 5)  
</li><li>     <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">false</font></b>;  
</li><li>   <b><font color="#0000ff">if</font></b> (inp_zip.trim().<b><font color="#0000ff">length</font></b>() &gt; 10)  
</li><li>     <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">false</font></b>;  
</li><li>   <b><font color="#0000ff">if</font></b> (inp_state.trim().<b><font color="#0000ff">length</font></b>() != 2)  
</li><li>     <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">false</font></b>;  
</li><li>   <b><font color="#0000ff">return</font></b> <b><font color="#0000ff"><a href="http://www.yesky.com/key/2629/137629.html" class="bluekey" target="_blank">true</a></font></b>;  
</li><li>  }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div><br />　　USAddress类实现AddressValidator接口，因此Customer对象使用USAddress实例作为验证客户地址过程的一部分是没有任何问题的。<br /><br />　　Listing 20.4: Customer Class Using the USAddress Class <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">class</font></b> Customer {  
</li><li>          …  
</li><li>          …  
</li><li> <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress() {  
</li><li>   <i><font color="#339900">//get an appropriate address validator </font></i></li><li>   AddressValidator validator = getValidator(type);  
</li><li>   <i><font color="#339900">//Polymorphic call to validate the address </font></i></li><li>   <b><font color="#0000ff">return</font></b> validator.isValidAddress(address, zip, state);  
</li><li> }  
</li><li> <b><font color="#0000ff">private</font></b> AddressValidator getValidator(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> custType) {  
</li><li>   AddressValidator validator = <b><font color="#0000ff">null</font></b>;  
</li><li>   <b><font color="#0000ff">if</font></b> (custType.equals(Customer.US)) {  
</li><li>     validator = <b><font color="#0000ff">new</font></b> USAddress();  
</li><li>   }  
</li><li>   <b><font color="#0000ff">return</font></b> validator;  
</li><li> }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div> <br /><p align="center"><img src="http://dev.yesky.com/imagelist/05/10/70op8i5elq39.bmp" height="206" width="383" /></p><br />Figure 20.2: Customer/USAddress Validator?Class Association <br /><br />　　但是当验证来自加拿大的客户时，就要对应用进行改进。这需要一个验证加拿大客户地址的验证类。让我们假设已经存在一个用来验证加拿大客户地址的使用工具类CAAddress。<br /><br />从下面的CAAdress类的实现，可以发现CAAdress提供了客户类Customer类所需要的验证服务。但是它所提供的接口不用于客户类Customer所期望的。<br /><br />　　Listing 20.5: CAAdress Class with Incompatible Interface <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">class</font></b> CAAddress {  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidCanadianAddr(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>     <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_pcode, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_prvnc) {  
</li><li>   <b><font color="#0000ff">if</font></b> (inp_address.trim().<b><font color="#0000ff">length</font></b>() &lt; 15)  
</li><li>     <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">false</font></b>;  
</li><li>   <b><font color="#0000ff">if</font></b> (inp_pcode.trim().<b><font color="#0000ff">length</font></b>() != 6)  
</li><li>     <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">false</font></b>;  
</li><li>   <b><font color="#0000ff">if</font></b> (inp_prvnc.trim().<b><font color="#0000ff">length</font></b>() &lt; 6)  
</li><li>     <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">false</font></b>;  
</li><li>   <b><font color="#0000ff">return</font></b> <b><font color="#0000ff">true</font></b>;  
</li><li>  }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div><br />　　CAAdress类提供了一个isValidCanadianAddr方法，但是Customer期望一个声明在AddressValidator接口中的isValidAddress方法。<br /><br />　　接口的不兼容使得Customer对象利用现有的CAAdress类是困难的。一种意见是改变CAAdress类的接口，但是可能会有其他的应用正在使用CAAdress类的这种形式。改变CAAdress类接口会影响现在使用CAAdress类的客户。<br /><br />　　应用适配器模式，类适配器CAAdressAdapter可以继承CAAdress类实现AddressValidator接口。<br /><br /> 
<p align="center"><img src="http://dev.yesky.com/imagelist/05/10/udtr40j091ei.bmp" /></p><br />　　Figure 20.3: Class Adapter for the CAAddress Class <br />Listing 20.6: CAAddressAdapter as a Class Adapter <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">class</font></b> CAAddressAdapter <b><font color="#0000ff">extends</font></b> CAAddress  
</li><li>  <b><font color="#0000ff">implements</font></b> AddressValidator {  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>     <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_zip, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_state) {  
</li><li>    <b><font color="#0000ff">return</font></b> isValidCanadianAddr(inp_address, inp_zip,  
</li><li>           inp_state);  
</li><li>  }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div><br />　
　因为适配器CAAdressAdapter实现了AddressValidator接口，客户端对象访问适配器CAAdressAdapter对象是没
有任何问题的。当客户对象调用适配器实例的isValidAddress方法的时候，适配器在内部把调用传递给它继承的
isValidCanadianAddr方法。<br /><br />　　在Customer类内部，getValidator私有方法需要扩展，以至于它可以
在验证加拿大客户的时候返回一个CAAdressAdapter实例。返回的对象是多态的，USAddress和CAAddressAdapter都实现
了AddressValidator接口，所以不用改变。<br /><br />Listing 20.7: Customer Class Using the CAAddressAdapter Class <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">class</font></b> Customer {  
</li><li>          …  
</li><li>          …  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress() {  
</li><li>    <i><font color="#339900">//get an appropriate address validator </font></i></li><li>    AddressValidator validator = getValidator(type);  
</li><li>    <i><font color="#339900">//Polymorphic call to validate the address </font></i></li><li>    <b><font color="#0000ff">return</font></b> validator.isValidAddress(address, zip, state);  
</li><li>  }  
</li><li>  <b><font color="#0000ff">private</font></b> AddressValidator getValidator(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> custType) {  
</li><li>    AddressValidator validator = <b><font color="#0000ff">null</font></b>;  
</li><li>    <b><font color="#0000ff">if</font></b> (custType.equals(Customer.US)) {  
</li><li>      validator = <b><font color="#0000ff">new</font></b> USAddress();  
</li><li>    }  
</li><li>    <b><font color="#0000ff">if</font></b> (type.equals(Customer.CANADA)) {  
</li><li>      validator = <b><font color="#0000ff">new</font></b> CAAddressAdapter();  
</li><li>    }  
</li><li>    <b><font color="#0000ff">return</font></b> validator;  
</li><li>  }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div>　　CAAddressAdapter设计和对AddressValidator（声明期望的接口）对象的多态调用使Customer可以利用接口不兼容CAAddress类提供的服务。<br /><br /> 
<p align="center"><img src="http://dev.yesky.com/imagelist/05/10/1f3c0ibb0e65.bmp" /></p><br />　　Figure 20.4: Address Validation Application?Using Class Adapter <br /><br /> 
<p align="center"><img src="http://dev.yesky.com/imagelist/05/10/c2t12b1g8856.bmp" /></p><br />　　Figure 20.5: Address Validation Message Flow?Using Class Adapter <br /><br />　　作为对象适配器的地址适配器<br /><br />　
　当讨论以类适配器来实现地址适配器时，我们说客户类期望的AddressValidator接口是Java接口形式。现在，让我们假设客户类期望
AddressValidator接口是抽象类而不是java接口。因为适配器CAAdapter必须提供抽象类AddressValidatro中声明
的接口，适配器必须是AddressValidator抽象类的子类、实现抽象方法。<br /><div class="codeStyle"><ol><li>Listing 20.8: AddressValidator as an Abstract <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/Class.java.html" target="_blank"><font class="classLink"><u>Class</u></font></a></b>  
</li><li><b><font color="#0000ff">public</font></b> <b><font color="#0000ff">abstract</font></b> <b><font color="#0000ff">class</font></b> AddressValidator {  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">abstract</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>     <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_zip, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_state);  
</li><li>}<i><font color="#339900">//end of class </font></i></li><li>Listing 20.9: CAAddressAdapter <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/Class.java.html" target="_blank"><font class="classLink"><u>Class</u></font></a></b>  
</li><li><b><font color="#0000ff">class</font></b> CAAddressAdapter <b><font color="#0000ff">extends</font></b> AddressValidator {  
</li><li>          …  
</li><li>          …  
</li><li>  <b><font color="#0000ff">public</font></b> CAAddressAdapter(CAAddress address) {  
</li><li>    objCAAddress = address;  
</li><li>  }  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>     <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_zip, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_state) {  
</li><li>          …  
</li><li>          …  
</li><li>  }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div><br />　　因为多继承在JAVA中不支持，现在适配器CAAddressAdapter不能继承现有的CAAddress类，它已经使用了唯一一次继承其他类的机会。<br /><br />　　应用对象适配器模式，CAAddressAdapter可以包含一个适配者CAAddress的一个实例。当适配器第一次创建的时候，这个适配者的实例通过客户端传递给适配器。通常，适配者实例可以通过下面两种方式提供给包装它的适配器。<br /><br />　　（1）    对象适配器的客户端可以传递一个适配者的实例给适配器。这种方式在选择类的形式上有很大的灵活性，但是客户端感知了适配者或者适配过程。这种方法在适配器不但需要适配者对象行为而且需要特定状态时很适合。<br /><br />　　（2）    适配器可以自己创建适配者实例。这种方法相对来说缺乏灵活性。适用于适配器只需要适配者对象的行为而不需要适配者对象的特定状态的情况。<br /><br /> 
<p align="center"><img src="http://dev.yesky.com/imagelist/05/10/2wu05ssw243c.bmp" /></p><br />　　Figure 20.6: Object Adapter for the CAAddress Class <br /><br />　　Listing 20.10: CAAddressAdapter as an Object Adapter <br /><div class="codeStyle"><ol><li><b><font color="#0000ff">class</font></b> CAAddressAdapter <b><font color="#0000ff">extends</font></b> AddressValidator {  
</li><li>  <b><font color="#0000ff">private</font></b> CAAddress objCAAddress;  
</li><li>  <b><font color="#0000ff">public</font></b> CAAddressAdapter(CAAddress address) {  
</li><li>    objCAAddress = address;  
</li><li>  }  
</li><li>  <b><font color="#0000ff">public</font></b> <b><font color="#0000ff">boolean</font></b> isValidAddress(<b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_address,  
</li><li>     <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_zip, <b><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></b> inp_state) {  
</li><li>    <b><font color="#0000ff">return</font></b> objCAAddress.isValidCanadianAddr(inp_address,  
</li><li>           inp_zip, inp_state);  
</li><li>  }  
</li><li>}<i><font color="#339900">//end of class </font></i></li></ol></div><br />　　当客户对象调用CAAddressAdapter（adapter）上的isValidAddress方法时, 适配器在内部调用CAAddress(adaptee)上的isValidCanadianAddr方法。<br /><br /><br /> 
<p align="center"><img src="http://dev.yesky.com/imagelist/05/10/n28i18m48296.bmp" /></p><br />　　Figure 20.7: Address Validation Application?Using Object Adapter <br /><br />　　从这个例子可以看出，适配器可以使Customer（client）类访问借口不兼容的CAAddress(adaptee)所提供的服务！<br /><br /> 
<p align="center"><img src="http://dev.yesky.com/imagelist/05/10/yy95r5qc5l6o.bmp" /></p><br /><br />　　Figure 20.8: Address Validation Message Flow?Using Object Adapter <br /><img src ="http://www.blogjava.net/alex/aggbug/67332.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-03 00:02 <a href="http://www.blogjava.net/alex/archive/2006/09/03/67332.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之Template</title><link>http://www.blogjava.net/alex/archive/2006/09/02/67325.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sat, 02 Sep 2006 15:16:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/02/67325.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/67325.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/02/67325.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/67325.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/67325.html</trackback:ping><description><![CDATA[
		<p>Template模板模式定义:<br />
                    定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中.</p>
		<p>使用Java的抽象类时，就经常会使用到Template模式,因此Template模式使用很普遍.而且很容易理解和使用。</p>
		<p> </p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">public abstract class Benchmark<br />
                        {<br />
                        　　/**<br />
                        　　* 下面操作是我们希望在子类中完成<br />
                        　　*/<br />
                        　　public abstract void benchmark(); 
                        <p> 　　/**<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();</p><p> 　　　　for (int i = 0; i &lt; count; i++) <br />
                          　　　　　　benchmark();<br /><br />
                          　　　　long stopTime = System.currentTimeMillis();<br />
                          　　　　return stopTime - startTime;<br />
                          　　}<br />
                          }<br />
                          }<br /></p></td>
						</tr>
				</tbody>
		</table>
		<p>在上例中,我们希望重复执行benchmark()操作,但是对benchmark()的具体内容没有说明,而是延迟到其子类中描述:</p>
		<table border="0" cellpadding="3" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td bgcolor="#cccccc">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 /></td>
						</tr>
				</tbody>
		</table>
		<p>至此,Template模式已经完成,是不是很简单?</p>
		<p>我们称repeat方法为模板方法， 它其中的benchmark()实现被延迟到子类MethodBenchmark中实现了，</p>
		<p>看看如何使用:</p>
		<p> Benchmark operation = new MethodBenchmark();<br />
                    long duration = operation.repeat(Integer.parseInt(args[0].trim()));<br />
                    System.out.println("The operation took " + duration 
                    + " milliseconds");</p>
		<p> </p>
		<p>也许你以前还疑惑抽象类有什么用,现在你应该彻底明白了吧? 至于这样做的好处,很显然啊,扩展性强,以后Benchmark内容变化,我只要再做一个继承子类就可以,不必修改其他应用代码.</p>
<img src ="http://www.blogjava.net/alex/aggbug/67325.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-02 23:16 <a href="http://www.blogjava.net/alex/archive/2006/09/02/67325.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之Command</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66948.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 13:46:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66948.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66948.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66948.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66948.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66948.html</trackback:ping><description><![CDATA[
		<p>Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才
对自己实际编程有指导作用.Command模式实际上不是个很具体,规定很多的模式,正是这个灵活性,让人有些confuse.</p>
		<p>
				<b>Command定义</b>
				<br />
n 将来自客户端的请求传入一个对象，无需了解这个请求激活的 动作或有关接受这个请求的处理细节。</p>
		<p>这是一种两台机器之间通讯联系性质的模式，类似传统过程语
  言的 CallBack功能。
</p>
		<p>
				<strong>优点：<br /></strong>解耦了发送者和接受者之间联系。 发送者调用一个操作，接受者接受请求执行相应的动作，因为使用Command模式解耦，发送者无需知道接受者任何接口。</p>
		<p>不少Command模式的代码都是针对图形界面的,它实际就是菜单命令,我们在一个下拉菜单选择一个命令时,然后会执行一些动作.</p>
		<p>将
这些命令封装成在一个类中,然后用户(调用者)再对这个类进行操作,这就是Command模式,换句话说,本来用户(调用者)是直接调用这些命令的,如菜
单上打开文档(调用者),就直接指向打开文档的代码,使用Command模式,就是在这两者之间增加一个中间者,将这种直接关系拗断,同时两者之间都隔
离,基本没有关系了.</p>
		<p>显然这样做的好处是符合封装的特性,降低耦合度,Command是将对行为进行封装的典型模式,Factory是将创建进行封装的模式,<br />
        从Command模式,<font color="#ff0000"><b>我也发现设计模式一个"通病":好象喜欢将简单的问题复杂化, 喜欢在不同类中增加第三者,当然这样做有利于代码的健壮性 
        可维护性 还有复用性.</b></font></p>
		<p>
				<b>如何使用?</b>
				<br />
具体的Command模式代码各式各样,因为如何封装命令,不同系统,有不同的做法.下面事例是将命令封装在一个Collection的List中,任何
对象一旦加入List中,实际上装入了一个封闭的黑盒中,对象的特性消失了,只有取出时,才有可能模糊的分辨出:</p>
      典型的Command模式需要有一个接口.接口中有一个统一的方法,这就是"将命令/请求封装为对象":<br /><table border="0" cellpadding="3" cellspacing="3" width="80%"><tbody><tr><td bgcolor="#cccccc">public interface Command {<br />
            　　public abstract void execute ( );<br />
            }</td></tr></tbody></table><br />
      具体不同命令/请求代码是实现接口Command,下面有三个具体命令<br /><table bgcolor="#cccccc" border="0" cellpadding="3" cellspacing="3" width="80%"><tbody><tr><td>public class Engineer implements Command {<br /><br />
            　　public void execute( ) {<br />
            　　　　//do Engineer's command<br />
            　　}<br />
            } 
            <p>public class Programmer implements Command {<br /><br />
              　　public void execute( ) {<br />
              　　　　//do programmer's command<br />
              　　}<br />
              }</p><p>public class Politician implements Command {<br /><br />
              　　public void execute( ) {<br />
              　　　　//do Politician's command<br />
              　　}<br />
              }</p></td></tr></tbody></table><br /><p>按照通常做法,我们就可以直接调用这三个Command,但是使用Command模式,我们要将他们封装起来,扔到黑盒子List里去:<br /></p><table border="0" cellpadding="3" cellspacing="3" width="80%"><tbody><tr><td bgcolor="#cccccc"><p>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 />
              　　}</p><p>}</p></td></tr></tbody></table><p><font color="#ff0000"> 这三个命令进入List中后,已经失去了其外表特征,以后再取出,也可能无法分辨出谁是Engineer 谁是Programmer了,看下面客户端如何调用Command模式:</font><br /></p><table border="0" cellpadding="3" cellspacing="3" width="80%"><tbody><tr><td bgcolor="#cccccc"><p>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 />
              　　　　　　<br />
               　//客户端直接调用execute方法，无需知道被调用者的其它更多类的方法名。<br />
              　　　　(<font color="#ff0000">(Command)it.next()).execute()</font>;<br />
              　　</p><p> 　　}<br />
              } </p></td></tr></tbody></table><p><font color="#ff0000"> 由此可见,调用者基本只和接口打交道,不合具体实现交互,这也体现了一个原则,面向接口编程</font>,这样,以后增加第四个具体命令时,就不必修改调用者TestCommand中的代码了.<br /><br />
        理解了上面的代码的核心原理,在使用中,就应该各人有自己方法了,特别是在如何分离调用者和具体命令上,有很多实现方法,上面的代码是使用"从List过一遍"的做法.这种做法只是为了演示.<br /></p><p><font color="#ff0000">使用Command模式的一个好理由还因为它能实现Undo功能.每个具体命令都可以记住它刚刚执行的动作,并且在需要时恢复.</font></p><p><font color="#ff0000">Command模式在界面设计中应用广泛</font>.Java的Swing中菜单命令都是使用Command模式,由于Java在界面设计的性能上还有欠缺,因此界面设计具体代码我们就不讨论,网络上有很多这样的示例.</p><p>参考:<br /><a href="http://www.patterndepot.com/put/8/command.pdf" target="_blank">http://www.patterndepot.com/put/8/command.pdf 
        </a></p><p><a href="http://www.javaworld.com/javaworld/javatips/jw-javatip68.html" target="_blank">http://www.javaworld.com/javaworld/javatips/jw-javatip68.html</a></p><img src ="http://www.blogjava.net/alex/aggbug/66948.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 21:46 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66948.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出组合模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66519.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 13:44:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66519.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66519.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66519.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66519.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66519.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">一、</span>
				</span>
				<span style="font-family: 宋体;">引子</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">在大学的数据结构这门课上，树是最重要的章节之一。还记得树是怎么定义的吗？树</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">(Tree)</span>
				<span style="font-family: 宋体;">是</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">n(n≥0)</span>
				<span style="font-family: 宋体;">个结点的有限集</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">T</span>
				<span style="font-family: 宋体;">，</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">T</span>
				<span style="font-family: 宋体;">为空时称为空树，否则它满足如下两个条件：</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 39pt; text-indent: -18pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">(1)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">    </span></span>
				</span>
				<span style="font-family: 宋体;">有且仅有一个特定的称为根</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">(Root)</span>
				<span style="font-family: 宋体;">的结点；</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 39pt; text-indent: -18pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">(2)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">   </span></span>
				</span>
				<span style="font-family: 宋体;">其余的结点可分为</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">m(m≥0)</span>
				<span style="font-family: 宋体;">个互不相交的子集</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Tl</span>
				<span style="font-family: 宋体;">，</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">T2</span>
				<span style="font-family: 宋体;">，</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">…</span>
				<span style="font-family: 宋体;">，</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Tm</span>
				<span style="font-family: 宋体;">，其中每个子集本身又是一棵树，并称其为根的子树</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">(SubTree)</span>
				<span style="font-family: 宋体;">。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">上面给出的递归定义刻画了树的固有特性：一棵非空树是由若干棵子树构成的，而子树又可由若干棵更小的子树构成。而这里的子树可以是叶子也可以是分支。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">今天要学习的组合模式就是和树型结构以及递归有关系。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">二、</span>
				</span>
				<span style="font-family: 宋体;">定义与结构</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">组合</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">(Composite)</span>
				<span style="font-family: 宋体;">模式的其它翻译名称也很多，比如合成模式、树模式等等。在《设计模式》一书中给出的定义是：将对象以树形结构组织起来，以达成</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">“</span>
				<span style="font-family: 宋体;">部分－整体</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">”</span>
				<span style="font-family: 宋体;">的层次结构，使得客户端对单个对象和组合对象的使用具有一致性。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">从定义中可以得到使用组合模式的环境为：</span>
				<span style="font-family: 宋体;">在设计中想表示对象的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">“</span>
				<span style="font-family: 宋体;">部分</span>
				<span style="font-family: 宋体;">－</span>
				<span style="font-family: 宋体;">整体</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">”</span>
				<span style="font-family: 宋体;">层次结构；希望用户忽略组合对象与单个对象的不同，统一地使用组合结构中的所有对象。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">看下组合模式的组成。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">1)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">         </span></span>
				</span>
				<span style="font-family: 宋体;">抽象构件角色</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Component</span>
				<span style="font-family: 宋体;">：它为组合中的对象声明接口，也可以为共有接口实现缺省行为。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">2)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">       </span></span>
				</span>
				<span style="font-family: 宋体;">树叶构件角色</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Leaf</span>
				<span style="font-family: 宋体;">：在组合中表示叶节点对象</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">——</span>
				<span style="font-family: 宋体;">没有子节点，实现抽象构件角色声明的接口。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">3)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">       </span></span>
				</span>
				<span style="font-family: 宋体;">树枝构件角色</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Composite</span>
				<span style="font-family: 宋体;">：在组合中表示分支节点对象</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">——</span>
				<span style="font-family: 宋体;">有子节点，实现抽象构件角色声明的接口；存储子部件。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">下图为组合模式的类图表示。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: center;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
								<v:stroke joinstyle="miter">
								</v:stroke>
								<v:formulas>
										<v:f eqn="if lineDrawn pixelLineWidth 0">
										</v:f>
										<v:f eqn="sum @0 1 0">
										</v:f>
										<v:f eqn="sum 0 0 @1">
										</v:f>
										<v:f eqn="prod @2 1 2">
										</v:f>
										<v:f eqn="prod @3 21600 pixelWidth">
										</v:f>
										<v:f eqn="prod @3 21600 pixelHeight">
										</v:f>
										<v:f eqn="sum @0 0 1">
										</v:f>
										<v:f eqn="prod @6 1 2">
										</v:f>
										<v:f eqn="prod @7 21600 pixelWidth">
										</v:f>
										<v:f eqn="sum @8 21600 0">
										</v:f>
										<v:f eqn="prod @7 21600 pixelHeight">
										</v:f>
										<v:f eqn="sum @10 21600 0">
										</v:f>
								</v:formulas>
								<v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
								</v:path>
								<o:lock aspectratio="t" v:ext="edit">
								</o:lock>
						</v:shapetype>
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
								<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_composite1.jpg" align="bottom" border="0" hspace="0" />
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"> </p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">如图所示：一个</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Composite</span>
				<span style="font-family: 宋体;">实例可以像一个简单的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Leaf</span>
				<span style="font-family: 宋体;">实例一样，可以把它传递给任何使用</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Component</span>
				<span style="font-family: 宋体;">的方法或者对象，并且它表现的就像是一个</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Leaf</span>
				<span style="font-family: 宋体;">一样。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">可以看出来，使用组合模式使得这个设计结构非常灵活，在下面的例子中会得到进一步的印证。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">三、</span>
				</span>
				<span style="font-family: 宋体;">安全性与透明性</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">组合模式中必须提供对子对象的管理方法，不然无法完成对子对象的添加删除等等操作，也就失去了灵活性和扩展性。但是管理方法是在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Component</span>
				<span style="font-family: 宋体;">中就声明还是在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Composite</span>
				<span style="font-family: 宋体;">中声明呢？</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">一种方式是在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Component</span>
				<span style="font-family: 宋体;">里面声明所有的用来管理子类对象的方法，以达到</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Component</span>
				<span style="font-family: 宋体;">接口的最大化（如下图所示）。目的就是为了使客户看来在接口层次上树叶和分支没有区别</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">——</span>
				<span style="font-family: 宋体;">透明性。但树叶是不存在子类的，因此</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Component</span>
				<span style="font-family: 宋体;">声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
								<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_composite2.jpg" align="bottom" border="0" hspace="0" />
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"> </p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">另一种方式就是只在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Composite</span>
				<span style="font-family: 宋体;">里面声明所有的用来管理子类对象的方法（如下图所示）。这样就避免了上一种方式的安全性问题，但是由于叶子和分支有不同的接口，所以又失去了透明性。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: center;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">    </span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;" align="center">
				<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_composite3.jpg" align="bottom" border="0" hspace="0" />
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<br />    《设计模式》一书认为：在这一模式中，相对于安全性，我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。<span style="font-family: 'Comic Sans MS';" lang="EN-US"><o:p></o:p></span></p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">四、</span>
				</span>
				<span style="font-family: 宋体;">举例</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">这里以</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">JUnit</span>
				<span style="font-family: 宋体;">中的组合模式的应用为例（<span style="font-family: 'Comic Sans MS';" lang="EN-US"><a href="http://blog.csdn.net/ai92/archive/2005/02/26/302844.aspx">JUnit<span style="font-family: 宋体;" lang="EN-US"><span lang="EN-US">入<span lang="EN-US">门</span></span></span></a></span>）。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">JUnit</span>
				<span style="font-family: 宋体;">是一个单元测试框架，按照此框架下的规范来编写测试代码，就可以使单元测试自动化。为了达到“自动化”的目的，</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">JUnit</span>
				<span style="font-family: 宋体;">中定义了两个概念：</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">和</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">是对一个类或者</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">jsp</span>
				<span style="font-family: 宋体;">等等编写的测试类；而</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">是一个不同</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">的集合，当然这个集合里面也可以包含</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">元素，这样运行一个</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">会将其包含的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">全部运行。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">然而在真实运行测试程序的时候，是不需要关心这个类是</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">还是</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">，我们只关心测试运行结果如何。这就是为什么</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">JUnit</span>
				<span style="font-family: 宋体;">使用组合模式的原因。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">JUnit</span>
				<span style="font-family: 宋体;">为了采用组合模式将</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">和</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">统一起来，创建了一个</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Test</span>
				<span style="font-family: 宋体;">接口来扮演抽象构件角色，这样原来的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">扮演组合模式中树叶构件角色，而</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">扮演组合模式中的树枝构件角色。下面将这三个类的有关代码分析如下：</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//Test</span>
				<span style="font-family: 宋体;">接口</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">——</span>
				<span style="font-family: 宋体;">抽象构件角色</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public interface Test {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>/**<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>* Counts the number of test cases that will be run by this test.<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>*/<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public abstract int countTestCases();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>/**<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>* Runs a test and collects its result in a TestResult instance.<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>*/<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public abstract void run(TestResult result);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//TestSuite</span>
				<span style="font-family: 宋体;">类的部分有关源码</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">——Composite</span>
				<span style="font-family: 宋体;">角色，它实现了接口</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Test<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public class TestSuite implements Test {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">用了较老的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Vector</span>
				<span style="font-family: 宋体;">来保存添加的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">test<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>private Vector fTests= new Vector(10);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>private String fName;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>……<span style="">  </span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">/**<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>* Adds a test to the suite.<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>*/<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public void addTest(Test test) {<span style="">           </span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">注意这里的参数是</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Test</span>
				<span style="font-family: 宋体;">类型的。这就意味着</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestCase</span>
				<span style="font-family: 宋体;">和</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">TestSuite</span>
				<span style="font-family: 宋体;">以及以后实现</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">Test</span>
				<span style="font-family: 宋体;">接口的任何类都可以被添加进来</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>fTests.addElement(test);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>……<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>/**<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>* Counts the number of test cases that will be run by this test.<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>*/<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public int countTestCases() {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>int count= 0;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>for (Enumeration e= tests(); e.hasMoreElements(); ) {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>Test test= (Test)e.nextElement();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>count= count + test.countTestCases();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>return count;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>} <o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>/**<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>* Runs the tests and collects their result in a TestResult.<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>*/<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public void run(TestResult result) {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>for (Enumeration e= tests(); e.hasMoreElements(); ) {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style="">  </span>
						<span style="">           </span>if (result.shouldStop() )<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style="">  </span>
						<span style="">                  </span>break;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>Test test= (Test)e.nextElement();<br />                           //关键在这个方法上面<br /><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>runTest(test, result);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<br />            //这个方法里面就是递归的调用了，至于你的Test到底是什么类型的只有在运行的时候得知<br />            public void runTest(Test test, TestResult result) {<br />                   test.run(result);<br />            }<br /><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">……<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//TestCase</span>
				<span style="font-family: 宋体;">的部分有关源码</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">——Leaf</span>
				<span style="font-family: 宋体;">角色，你编写的测试类就是继承自它</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public abstract class TestCase extends Assert implements Test {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>……<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>/**<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>* Counts the number of test cases executed by run(TestResult result).<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>*/<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public int countTestCases() {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>return 1;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">/**<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>* Runs the test case and collects the results in TestResult.<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
						<span style=""> </span>*/<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public void run(TestResult result) {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>result.run(this);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">……<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">可以看出这是一个偏重安全性的组合模式。因此在使用TestCase和TestSuite时，不能使用Test来代替。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">五、</span>
				</span>
				<span style="font-family: 宋体;">优缺点</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: 宋体;">从上面的举例中可以看到，组合模式有以下优点：</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">1)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">         </span></span>
				</span>
				<span style="font-family: 宋体;">使客户端调用简单，客户端可以一致的使用组合结构或其中单个对象，用户就不必关心自己处理的是单个对象还是整个组合结构，这就简化了客户端代码。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">2)<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">       </span></span>
				</span>
				<span style="font-family: 宋体;">更容易在组合体内加入对象部件</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">. </span>
				<span style="font-family: 宋体;">客户端不必因为加入了新的对象部件而更改代码。这一点符合开闭原则的要求，对系统的二次开发和功能扩展很有利！</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: 宋体;">当然组合模式也少不了缺点：组合模式不容易限制组合中的构件。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">六、</span>
				</span>
				<span style="font-family: 宋体;">总结</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">组合模式是一个应用非常广泛的设计模式，在前面已经介绍过的解释器模式、享元模式中都是用到了组合模式。它本身比较简单但是很有内涵，掌握了它对你的开发设计有很大的帮助。</span>
		</p>
		<span style="font-family: 宋体;">这里写下了我学习组合模式的总结，希望能给你带来帮助，也希望您能给与指正。</span>
<img src ="http://www.blogjava.net/alex/aggbug/66519.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 21:44 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66519.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出模板方法模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66516.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 13:39:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66516.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66516.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66516.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66516.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66516.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">一、</span>
						</span>
						<span style="font-family: 宋体;">引子</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">这是一个很简单的模式，却被非常广泛的使用。之所以简单是因为在这个模式中仅仅使用到了继承关系。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">继承关系由于自身的缺陷，被专家们扣上了</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">罪恶</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">的帽子。</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">使用委派关系代替继承关系</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">，</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">尽量使用接口实现而不是抽象类继承</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">等等专家警告，让我们这些菜鸟对继承</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">另眼相看</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">其实，继承还是有很多自身的优点所在。只是被大家滥用的似乎缺点更加明显了。合理的利用继承关系，还是能对你的系统设计起到很好的作用的。而模板方法模式就是其中的一个使用范例。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">二、</span>
						</span>
						<span style="font-family: 宋体;">定义与结构</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">给模板方法（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Template Method</span>
						<span style="font-family: 宋体;">）模式定义一个操作中的算法的骨架，而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这里的算法的结构，可以理解为你根据需求设计出来的业务流程。特定的步骤就是指那些可能在内容上存在变数的环节。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">可以看出来，模板方法模式也是为了巧妙解决变化对系统带来的影响而设计的。使用模板方法使系统扩展性增强，最小化了变化对系统的影响。这一点，在下面的举例中可以很明显的看出来。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">来看下这个简单模式的结构吧：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">AbstractClass</span>
						<span style="font-family: 宋体;">（抽象类）：定义了一到多个的抽象方法，以供具体的子类来实现它们；而且还要实现一个模板方法，来定义一个算法的骨架。该模板方法不仅调用前面的抽象方法，也可以调用其他的操作，只要能完成自身的使命。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">ConcreteClass</span>
						<span style="font-family: 宋体;">（具体类）：实现父类中的抽象方法以完成算法中与特定子类相关的步骤。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">下面是模板方法模式的结构图。直接把《设计模式》上的图拿过来用下：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<p>
										<img src="http://blog.csdn.net/images/blog_csdn_net/ai92/105445/r_template.jpg" alt="" />
								</p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">  </span>
								<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
										<stroke joinstyle="miter">
										</stroke>
										<formulas>
												<f eqn="if lineDrawn pixelLineWidth 0">
												</f>
												<f eqn="sum @0 1 0">
												</f>
												<f eqn="sum 0 0 @1">
												</f>
												<f eqn="prod @2 1 2">
												</f>
												<f eqn="prod @3 21600 pixelWidth">
												</f>
												<f eqn="prod @3 21600 pixelHeight">
												</f>
												<f eqn="sum @0 0 1">
												</f>
												<f eqn="prod @6 1 2">
												</f>
												<f eqn="prod @7 21600 pixelWidth">
												</f>
												<f eqn="sum @8 21600 0">
												</f>
												<f eqn="prod @7 21600 pixelHeight">
												</f>
												<f eqn="sum @10 21600 0">
												</f>
										</formulas>
										<path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
										</path>
										<lock aspectratio="t" v:ext="edit">
										</lock>
								</shapetype>
								<shape id="_x0000_i1025" style="width: 342.75pt; height: 203.25pt;" type="#_x0000_t75">
										<imagedata o:title="" src="file:///C:%5CDOCUME%7E1%5CAI92%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png">
										</imagedata>
								</shape>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">三、</span>
						</span>
						<span style="font-family: 宋体;">举例</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">还是在我刚刚分析完源码的</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">中找个例子吧。</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">中的</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestCase</span>
						<span style="font-family: 宋体;">以及它的子类就是一个模板方法模式的例子。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestCase</span>
						<span style="font-family: 宋体;">这个抽象类中将整个测试的流程设置好了，比如先执行</span>
						<span style="font-family: Tahoma;" lang="EN-US">Setup</span>
						<span style="font-family: 宋体;">方法初始化测试前提，在运行测试方法，然后再</span>
						<span style="font-family: Tahoma;" lang="EN-US">TearDown</span>
						<span style="font-family: 宋体;">来取消测试设置。但是你将在</span>
						<span style="font-family: Tahoma;" lang="EN-US">Setup</span>
						<span style="font-family: 宋体;">、</span>
						<span style="font-family: Tahoma;" lang="EN-US">TearDown</span>
						<span style="font-family: 宋体;">里面作些什么呢？鬼才知道呢！！因此，而这些步骤的具体实现都延迟到子类中去，也就是你实现的测试类中。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">来看下相关的源代码吧。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">这是</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestCase</span>
						<span style="font-family: 宋体;">中，执行测试的模板方法。你可以看到，里面正像前面定义中所说的那样，它制定了“算法”的框架——先执行</span>
						<span style="font-family: Tahoma;" lang="EN-US">setUp</span>
						<span style="font-family: 宋体;">方法来做下初始化，然后执行测试方法，最后执行</span>
						<span style="font-family: Tahoma;" lang="EN-US">tearDown</span>
						<span style="font-family: 宋体;">释放你得到的资源。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public void runBare() throws Throwable {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>setUp();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>try {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>runTest();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>finally {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>tearDown();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">这
就是上面使用的两个方法。与定义中不同的是，这两个方法并没有被实现为抽象方法，而是两个空的无为方法（被称为钩子方法）。这是因为在测试中，我们并不是
必须要让测试程序使用这两个方法来初始化和释放资源的。如果是抽象方法，则子类们必须给它一个实现，不管用到用不到。这显然是不合理的。使用钩子方法，则
你在需要的时候，可以在子类中重写这些方法。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">protected void setUp() throws Exception {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">protected void tearDown() throws Exception {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">四、</span>
						</span>
						<span style="font-family: 宋体;">适用情况</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">根据上面对定义的分析，以及例子的说明，可以看出模板方法适用于以下情况：</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">1)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">一次性实现一个算法的不变的部分，并将可变的行为留给子类来实现。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">2)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。其实这可以说是一种好的编码习惯了。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">3)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">控制子类扩展。模板方法只在特定点调用操作，这样就只允许在这些点进行扩展。比如上面</span>
						<span style="font-family: Tahoma;" lang="EN-US">runBare</span>
						<span style="font-family: 宋体;">（）方法就只在</span>
						<span style="font-family: Tahoma;" lang="EN-US">runTest</span>
						<span style="font-family: 宋体;">前面适用</span>
						<span style="font-family: Tahoma;" lang="EN-US">setUp</span>
						<span style="font-family: 宋体;">方法。如果你不愿子类来修改你的模板方法定义的框架，你可以采用两种方式来做：一是在</span>
						<span style="font-family: Tahoma;" lang="EN-US">API</span>
						<span style="font-family: 宋体;">中不体现出你的模板方法；二、将你的模板方法置为</span>
						<span style="font-family: Tahoma;" lang="EN-US">final</span>
						<span style="font-family: 宋体;">就可以了。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">可以看出，使用模板方法模式可以将代码的公共行为提取出来，达到复用的目的。而且，在模板方法模式中，是由父类的模板方法来控制子类中的具体实现。这样你在实现子类的时候，根本不需要对业务流程有太多的了解。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">五、</span>
						</span>
						<span style="font-family: 宋体;">总结</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<span style="font-family: 宋体;">
				<font size="3">匆匆忙忙写完了。希望大家指正！</font>
		</span>
<img src ="http://www.blogjava.net/alex/aggbug/66516.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 21:39 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66516.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出门面模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66509.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 12:46:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66509.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66509.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66509.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66509.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">key words: 门面模式 facade模式<br /></span>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">一、</span>
						</span>
						<span style="font-family: 宋体;">引子</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">门面模式是非常简单的设计模式。</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<p>
				<font size="3"> </font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">二、</span>
						</span>
						<span style="font-family: 宋体;">定义与结构</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="left">
				<font size="3">
						<span style="font-family: 宋体;">门面模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">facade</span>
						<span style="font-family: 宋体;">）又称外观模式。</span>
						<span style="font-family: Tahoma;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">在《设计模式》一书中给出如下定义：为子系统中的一组接口提供一个一致的界面，</span>
						<span style="font-family: Tahoma;" lang="EN-US"> Facade</span>
						<span style="font-family: 宋体;">模式定义了一个高层接口，这个接口使得这一子系统更加容易使用。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="left">
				<font size="3">
						<span style="font-family: 宋体;">定义中提到的子系统是指在设计中为了降低复杂性根据一定的规则（比如业务、功能），对系统进行的划分。子系统中封装有一些类。客户程序在使用子系统的时候，可能会像下图一样零乱。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="center">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<p>
										<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_facade1.jpg" align="absmiddle" />
								</p>
						</span>
				</font>
		</p>
		<p>
				<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_facade1.jpg" align="absmiddle" />
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="right">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
								</shapetype>
								<stroke joinstyle="miter">
								</stroke>
								<formulas>
								</formulas>
								<f eqn="if lineDrawn pixelLineWidth 0">
								</f>
								<f eqn="sum @0 1 0">
								</f>
								<f eqn="sum 0 0 @1">
								</f>
								<f eqn="prod @2 1 2">
								</f>
								<f eqn="prod @3 21600 pixelWidth">
								</f>
								<f eqn="prod @3 21600 pixelHeight">
								</f>
								<f eqn="sum @0 0 1">
								</f>
								<f eqn="prod @6 1 2">
								</f>
								<f eqn="prod @7 21600 pixelWidth">
								</f>
								<f eqn="sum @8 21600 0">
								</f>
								<f eqn="prod @7 21600 pixelHeight">
								</f>
								<f eqn="sum @10 21600 0">
								</f>
								<path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
								</path>
								<lock aspectratio="t" v:ext="edit">
								</lock>
								<shape id="_x0000_i1025" style="width: 222pt; height: 167.25pt;" type="#_x0000_t75">
								</shape>
								<imagedata o:title="facade1" src="file:///C:%5CDOCUME%7E1%5CAI92%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.gif">
								</imagedata>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="left">
				<font size="3">
						<span style="font-family: 宋体;">在上面的实现方法中，客户类紧紧地依赖在子系统的实现上。子系统发生的变化，很可能要影响到客户类的调用。而且子系统在不断优化、可重用化的重构路上，会产生更多更小的类。这对使用子系统的客户类来说要完成一个工作流程，似乎要记住的接口太多了。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">门面模式就是为了解决这种问题而产生的。看看使用了门面模式后的图：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;" align="center">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<p>
										<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_facade2.jpg" />
								</p>
						</span>
				</font>
		</p>
		<p>
				<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_facade2.jpg" />
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<shape id="_x0000_i1026" style="width: 208.5pt; height: 163.5pt;" type="#_x0000_t75">
								</shape>
								<imagedata o:title="facade2" src="file:///C:%5CDOCUME%7E1%5CAI92%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_image002.gif">
								</imagedata>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">这样就减少了客户程序和子系统之间的耦合，增加了可维护性。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">很明显，门面模式有三个角色组成：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">门面角色（</span>
						<span style="font-family: Tahoma;" lang="EN-US">facade</span>
						<span style="font-family: 宋体;">）：这是门面模式的核心。它被客户角色调用，因此它熟悉子系统的功能。它内部根据客户角色已有的需求预定了几种功能组合。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">子系统角色：实现了子系统的功能。对它而言，</span>
						<span style="font-family: Tahoma;" lang="EN-US">façade</span>
						<span style="font-family: 宋体;">角色就和客户角色一样是未知的，它没有任何</span>
						<span style="font-family: Tahoma;" lang="EN-US">façade</span>
						<span style="font-family: 宋体;">角色的信息和链接。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">3)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">客户角色：调用</span>
						<span style="font-family: Tahoma;" lang="EN-US">façade</span>
						<span style="font-family: 宋体;">角色来完成要得到的功能。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p>
				<font size="3"> </font>
				<font size="3"> </font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">三、</span>
						</span>
						<span style="font-family: 宋体;">举例</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<font color="#ff0000">
								<span lang="EN-US">
										<font face="Times New Roman">Facade</font>
								</span>
						</font>
						<span style="font-family: 宋体;">
								<font color="#ff0000">一个典型应用就是进行数据库连接</font>。一般我们在每一次对数据库进行访问，都要进行以下操作：先得到</span>
						<span lang="EN-US">
								<font face="Times New Roman">connect</font>
						</span>
						<span style="font-family: 宋体;">实例，然后打开</span>
						<span lang="EN-US">
								<font face="Times New Roman">connect</font>
						</span>
						<span style="font-family: 宋体;">获得连接，得到一个</span>
						<span lang="EN-US">
								<font face="Times New Roman">statement</font>
						</span>
						<span style="font-family: 宋体;">，执行</span>
						<span lang="EN-US">
								<font face="Times New Roman">sql</font>
						</span>
						<span style="font-family: 宋体;">语句进行查询，得到查询结果集。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span lang="EN-US">
								<span style="">
										<font face="Times New Roman">       </font>
								</span>
						</span>
						<span style="font-family: 宋体;">我们可以将这些步骤提取出来，封装在一个类里面。这样，每次执行数据库访问只需要将必要的参数传递到这个类中就可以了。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span lang="EN-US">
								<span style="">
										<font face="Times New Roman">       </font>
								</span>
						</span>
						<span style="font-family: 宋体;">有兴趣可以在你正在进行的系统中实现一下。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<p>
								<font face="Times New Roman" size="3"> </font>
								<font face="Times New Roman" size="3"> </font>
						</p>
				</span>
		</p>
		<p>
				<font face="Times New Roman" size="3"> </font>
				<font face="Times New Roman" size="3"> </font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="" lang="EN-US">
								<span style="">
										<font face="Times New Roman">四、</font>
								</span>
						</span>
						<span style="font-family: 宋体;">使用环境和优点</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">《设计模式》给出了门面模式的使用环境：</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">1)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">当你要为一个复杂子系统提供一个简单接口时。在上面已经描述了原因。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">2)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">客户程序与抽象类的实现部分之间存在着很大的依赖性。引入</span>
						<span lang="EN-US">
								<font face="Times New Roman">facade</font>
						</span>
						<span style="font-family: 宋体;">将这个子系统与客户以及其他的子系统分离，可以提高子系统的独立性和可移植性（上面也提到了）。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">3)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">当你需要构建一个层次结构的子系统时，使用</span>
						<span lang="EN-US">
								<font face="Times New Roman">facade</font>
						</span>
						<span style="font-family: 宋体;">模式定义子系统中每层的入口点。如果子系统之间是相互依赖的，你可以让它们仅通过</span>
						<span lang="EN-US">
								<font face="Times New Roman">facade</font>
						</span>
						<span style="font-family: 宋体;">进行通讯，从而简化了它们之间的依赖关系。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">以下是它的优点：</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">1)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">它对客户屏蔽子系统组件，因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">2)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">它实现了子系统与客户之间的松耦合关系，而子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统的组件变化不会影响到它的客户。</span>
						<span lang="EN-US">
								<font face="Times New Roman">Facade</font>
						</span>
						<span style="font-family: 宋体;">模式有助于建立层次结构系统，也有助于对对象之间的依赖关系分层。</span>
						<span lang="EN-US">
								<font face="Times New Roman">Facade</font>
						</span>
						<span style="font-family: 宋体;">模式可以消除复杂的循环依赖关系。这一点在客户程序与子系统是分别实现的时候尤为重要。在大型软件系统中降低编译依赖性至关重要。在子系统类改变时，希望尽量减少重编译工作以节省时间。用</span>
						<span lang="EN-US">
								<font face="Times New Roman">Facade</font>
						</span>
						<span style="font-family: 宋体;">可以降低编译依赖性，限制重要系统中较小的变化所需的重编译工作。</span>
						<span lang="EN-US">
								<font face="Times New Roman">Facade</font>
						</span>
						<span style="font-family: 宋体;">模式同样也有利于简化系统在不同平台之间的移植过程，因为编译一个子系统一般不需要编译所有其他的子系统。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">3)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">如果应用需要，它并不限制它们使用子系统类。因此你可以让客户程序在系统易用性和通用性之间加以选择。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<p>
								<font face="Times New Roman" size="3"> </font>
						</p>
				</span>
		</p>
		<p>
				<font face="Times New Roman" size="3"> </font>
		</p>
		<p>
				<font face="Times New Roman" size="3"> </font>
				<font size="3">
						<font face="Times New Roman">
								<span style="" lang="EN-US">
										<span style="">五、</span>
								</span>
								<span lang="EN-US">java</span>
						</font>
						<span style="font-family: 宋体;">中的门面模式</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<font color="#ff0000">
								<span style="font-family: 宋体;">先来想想门面模式和我们已经讲过的哪个模式相像？答案就是</span>
								<span lang="EN-US">
										<a href="http://blog.csdn.net/ai92/archive/2004/12/08/209198.aspx">
												<span style="font-family: 宋体;" lang="EN-US">
														<span lang="EN-US">抽象工厂</span>
												</span>
												<span style="font-family: 宋体;" lang="EN-US">
														<span lang="EN-US">模式</span>
												</span>
										</a>
								</span>
						</font>
						<span style="font-family: 宋体;">
								<font color="#ff0000">。</font>两者虽然在分类上有所区别，但是都是为了方便客户程序的使用而建立。两者的不同应该在于门面模式不仅方便了客户的使用，而且隐藏了不该让客户知道的类（这些类仅仅为子系统的其他类服务）。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">但是在</span>
						<span lang="EN-US">
								<font face="Times New Roman">java</font>
						</span>
						<span style="font-family: 宋体;">语言中提供的包的概念已经能够很好的解决上面门面模式提到的问题。你可以把一个子系统放在一个包里面，里面要提供给外面访问的类定义为</span>
						<span lang="EN-US">
								<font face="Times New Roman">public</font>
						</span>
						<span style="font-family: 宋体;">，而不该公布的类就可以设计为非</span>
						<span lang="EN-US">
								<font face="Times New Roman">public</font>
						</span>
						<span style="font-family: 宋体;">。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">因此，在一定程度上，门面模式在</span>
						<span lang="EN-US">
								<font face="Times New Roman">java</font>
						</span>
						<span style="font-family: 宋体;">中基本上可以不使用了。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">标准的门面模式虽然可以不再使用，但是这种提供一个中间类或者中间方法来方便客户程序使用的思想应该值得我们来实践的</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span lang="EN-US">
						<p>
								<font face="Times New Roman" size="3"> </font>
								<font face="Times New Roman" size="3"> </font>
						</p>
				</span>
		</p>
		<p>
				<font face="Times New Roman" size="3"> </font>
				<font face="Times New Roman" size="3"> </font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="" lang="EN-US">
								<span style="">
										<font face="Times New Roman">六、</font>
								</span>
						</span>
						<span style="font-family: 宋体;">总结</span>
				</font>
				<span style="font-family: 宋体;">
						<font size="3"> </font>
						<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
								<font size="3">
										<span style="font-family: 宋体;">门面模式从整体来看，给我的感觉是，它对于使两层之间的调用粗颗粒化很有帮助，避免了大量细颗粒度的访问。这和</span>
										<span lang="EN-US">
												<font face="Times New Roman">SOA</font>
										</span>
										<span style="font-family: 宋体;">中的一些观点是相同的。</span>
								</font>
						</p>
						<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
								<span style="font-family: 宋体;">
										<font size="3">   门面模式大体介绍完了。请指正：）</font>
								</span>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">门面模式从整体来看，给我的感觉是，它对于使两层之间的调用粗颗粒化很有帮助，避免了大量细颗粒度的访问。这和</span>
						<span lang="EN-US">
								<font face="Times New Roman">SOA</font>
						</span>
						<span style="font-family: 宋体;">中的一些观点是相同的。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 宋体;">
						<font size="3">   门面模式大体介绍完了。请指正：）</font>
				</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 20:46 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出单例模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66499.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 11:05:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66499.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66499.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66499.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66499.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66499.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">一、</span>
				</span>
				<span style="font-family: 宋体;">引子</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">单例模式是设计模式中使用很频繁的一种模式，在各种开源框架、应用系统中多有应用，在我前面的几篇文章中也结合其它模式使用到了单例模式。这里我们就单例模式进行系统的学习。并对有人提出的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">“</span>
				<span style="font-family: 宋体;">单例模式是邪恶的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">”</span>
				<span style="font-family: 宋体;">这个观点进行了一定的分析。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">二、</span>
				</span>
				<span style="font-family: 宋体;">定义与结构</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">单例模式又叫做单态模式或者单件模式。在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">GOF</span>
				<span style="font-family: 宋体;">书中给出的定义为：保证一个类仅有一个实例，并提供一个访问它的全局访问点。单例模式中的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">“</span>
				<span style="font-family: 宋体;">单例</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">”</span>
				<span style="font-family: 宋体;">通常用来代表那些本质上具有唯一性的系统组件（或者叫做资源）。比如文件系统、资源管理器等等。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">单
例模式的目的就是要控制特定的类只产生一个对象，当然也允许在一定情况下灵活的改变对象的个数。那么怎么来实现单例模式呢？一个类的对象的产生是由类构造
函数来完成的，如果想限制对象的产生，就要将构造函数变为私有的（至少是受保护的），使得外面的类不能通过引用来产生对象；同时为了保证类的可用性，就必
须提供一个自己的对象以及访问这个对象的静态方法。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">现在对单例模式有了大概的了解了吧，其实单例模式在实现上是非常简单的</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">——</span>
				<span style="font-family: 宋体;">只有一个角色，而客户则通过调用类方法来得到类的对象。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">放上一个类图吧，这样更直观一些：</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
								<v:stroke joinstyle="miter">
								</v:stroke>
								<v:formulas>
										<v:f eqn="if lineDrawn pixelLineWidth 0">
										</v:f>
										<v:f eqn="sum @0 1 0">
										</v:f>
										<v:f eqn="sum 0 0 @1">
										</v:f>
										<v:f eqn="prod @2 1 2">
										</v:f>
										<v:f eqn="prod @3 21600 pixelWidth">
										</v:f>
										<v:f eqn="prod @3 21600 pixelHeight">
										</v:f>
										<v:f eqn="sum @0 0 1">
										</v:f>
										<v:f eqn="prod @6 1 2">
										</v:f>
										<v:f eqn="prod @7 21600 pixelWidth">
										</v:f>
										<v:f eqn="sum @8 21600 0">
										</v:f>
										<v:f eqn="prod @7 21600 pixelHeight">
										</v:f>
										<v:f eqn="sum @10 21600 0">
										</v:f>
								</v:formulas>
								<v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
								</v:path>
								<o:lock aspectratio="t" v:ext="edit">
								</o:lock>
						</v:shapetype>
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
								<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_singleton.jpg" align="bottom" border="0" hspace="0" />
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"> </p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">单例模式可分为有状态的和无状态的。有状态的单例对象一般也是可变的单例对象，</span>
				<span style="font-family: 宋体;">多个单态对象在一起就可以作为一个状态仓库一样向外提供服务。没有状态的单例对象也就是不变单例对象，仅用做提供工具函数。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">三、</span>
				</span>
				<span style="font-family: 宋体;">实现</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">在单例模式的实现上有几种不同的方式，我在这里将一一讲解。先来看一种方式，它在《</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">与模式》中被称为饿汉式。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public class Singleton {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">在自己内部定义自己一个实例</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">注意这是</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">private </span>
				<span style="font-family: 宋体;">只供内部调用</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">private static Singleton instance = new Singleton();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">如上面所述，将构造函数设置为私有</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">private Singleton(){<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">}</span>
				<span style="font-family: 宋体;">　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">静态工厂方法，</span>
				<span style="font-family: 宋体;">提供了一个供外部访问得到对象</span>
				<span style="font-family: 宋体;">的静态方法　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<br />
				</span>
				<span style="font-family: 宋体;">　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public static Singleton getInstance() {<br /></span>
				<span style="font-family: 宋体;">　　　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">return instance; </span>
				<span style="font-family: 宋体;">　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<br />
				</span>
				<span style="font-family: 宋体;">　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">} <br />} <o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">下面这种方式被称为懒汉式：</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">P<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public class Singleton { <o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>//</span>
				<span style="font-family: 宋体;">和上面有什么不同？</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">private static Singleton instance = null;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">设置为私有的构造函数</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">private Singleton(){<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">}</span>
				<span style="font-family: 宋体;">　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">静态工厂方法</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public static <span style="background: yellow none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">synchronized</span> Singleton getInstance() {<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">这个方法比上面有所改进</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<br />
				</span>
				<span style="font-family: 宋体;">　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">if (instance==null)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">instance</span>
				<span style="font-family: 宋体;">＝</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">new Singleton();<br /></span>
				<span style="font-family: 宋体;">　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">return instance; </span>
				<span style="font-family: 宋体;">　　</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">} <o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">} <o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">先让我们来比较一下这两种实现方式。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">首先他们的构造函数都是私有的，彻底断开了使用构造函数来得到类的实例的通道，但是这样也使得类失去了多态性（大概这就是为什么有人将这种模式称作单态模式）。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">  </span>
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">在第二种方式中，对静态工厂方法进行了同步处理，原因很明显——为了防止多线程环境中产生多个实例；而在第一种方式中则不存在这种情况。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">在第二种方式中将类对自己的实例化延迟到第一次被引用的时候。而在第一种方式中则是在类被加载的时候实例化，这样多次加载会照成多次实例化。但是第二种方式由于使用了同步处理，在反应速度上要比第一种慢一些。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">在</span>
				<span style="font-family: 'Comic Sans MS';">
				</span>
				<span style="font-family: 宋体;">《</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">与模式》书中提到，就</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">语言来说，第一种方式更符合</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">语言本身的特点。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">以
上两种实现方式均失去了多态性，不允许被继承。还有另外一种灵活点的实现，将构造函数设置为受保护的，这样允许被继承产生子类。这种方式在具体实现上又有
所不同，可以将父类中获得对象的静态方法放到子类中再实现；也可以在父类的静态方法中进行条件判断来决定获得哪一个对象；在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">GOF</span>
				<span style="font-family: 宋体;">中认为最好的一种方式是维护一张存有对象和对应名称的注册表（可以使用</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">HashMap</span>
				<span style="font-family: 宋体;">来实现）。下面的实现参考《</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">与模式》采用带有注册表的方式。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">import java.util.HashMap;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public class Singleton<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">//</span>
				<span style="font-family: 宋体;">用来存放对应关系</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>private static HashMap sinRegistry = new HashMap();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>static private Singleton s = new Singleton();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>//</span>
				<span style="font-family: 宋体;">受保护的构造函数</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>protected Singleton()<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>{}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public static Singleton getInstance(String name)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>if(name == null)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>name = "Singleton";<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>if(sinRegistry.get(name)==null)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>try{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                            </span>sinRegistry.put(name , Class.forName(name).newInstance());<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>}catch(Exception e)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                            </span>e.printStackTrace();<span style=""></span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">                     </span>}<span style="">      </span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>return (Singleton)(sinRegistry.get(name));<span style="">  </span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public void test()<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>System.out.println("getclasssuccess!");<span style="">       </span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public class SingletonChild1 extends Singleton<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public SingletonChild1(){}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>static <span style="">   </span>public SingletonChild1 getInstance()<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>return (SingletonChild1)Singleton.getInstance("SingletonChild1");<span style="">      </span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>public void test()<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">              </span>System.out.println("getclasssuccess111!");<span style="">  </span><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">中子类的构造函数的范围不能比父类的小，所以可能存在不守规则的客户程序使用其构造函数来产生实例。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">四、单例模式邪恶论</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">看这题目也许有点夸张，不过这对初学者是一个很好的警告。单例模式在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">中的使用存在很多陷阱和假象，这使得没有意识到单例模式使用局限性的你在系统中布下了隐患……</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">其实这个问题早在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">2001</span>
				<span style="font-family: 宋体;">年的时候就有人在网上系统的提出来过，我在这里只是老生常谈了。但是对于大多的初学者来说，可能这样的观点在还很陌生。下面我就一一列举出单例模式在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">中存在的陷阱。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">多个虚拟机</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">当系统中的单例类被拷贝运行在多个虚拟机下的时候，在每一个虚拟机下都可以创建一个实例对象。在使用了</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">EJB</span>
				<span style="font-family: 宋体;">、</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">JINI</span>
				<span style="font-family: 宋体;">、</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">RMI</span>
				<span style="font-family: 宋体;">技术的分布式系统中，由于中间件屏蔽掉了分布式系统在物理上的差异，所以对你来说，想知道具体哪个虚拟机下运行着哪个单例对象是很困难的。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">因此，在使用以上分布技术的系统中，应该避免使用存在状态的单例模式，因为一个有状态的单例类，在不同虚拟机上，各个单例对象保存的状态很可能是不一样的，问题也就随之产生。而且在</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">EJB</span>
				<span style="font-family: 宋体;">中不要使用单例模式来控制访问资源，因为这是由</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">EJB</span>
				<span style="font-family: 宋体;">容器来负责的。在其它的分布式系统中，当每一个虚拟机中的资源是不同的时候，可以考虑使用单例模式来进行管理。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">多个类加载器</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">当存在多个类加载器加载类的时候，即使它们加载的是相同包名，相同类名甚至每个字节都完全相同的类，也会被区别对待的。因为不同的类加载器会使用不同的命名空间（</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">namespace</span>
				<span style="font-family: 宋体;">）来区分同一个类。因此，单例类在多加载器的环境下会产生多个单例对象。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">也许你认为出现多个类加载器的情况并不是很多。其实多个类加载器存在的情况并不少见。在很多</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">J2EE</span>
				<span style="font-family: 宋体;">服务器上允许存在多个</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">servlet</span>
				<span style="font-family: 宋体;">引擎，而每个引擎是采用不同的类加载器的；浏览器中</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">applet</span>
				<span style="font-family: 宋体;">小程序通过网络加载类的时候，由于安全因素，采用的是特殊的类加载器，等等。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">这种情况下，由状态的单例模式也会给系统带来隐患。因此除非系统由协调机制，在一般情况下不要使用存在状态的单例模式。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">错误的同步处理</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">在使用上面介绍的懒汉式单例模式时，同步处理的恰当与否也是至关重要的。不然可能会达不到得到单个对象的效果，还可能引发死锁等错误。因此在使用懒汉式单例模式时一定要对同步有所了解。不过使用饿汉式单例模式就可以避免这个问题。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">子类破坏了对象控制</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">在上一节介绍最后一种扩展性较好的单例模式实现方式的时候，就提到，由于类构造函数变得不再私有，就有可能失去对对象的控制。这种情况只能通过良好的文档来规范。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">串行化（可序列化）</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">为了使一个单例类变成可串行化的，仅仅在声明中添加“</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">implements Serializable</span>
				<span style="font-family: 宋体;">”是不够的。因为一个串行化的对象在每次返串行化的时候，都会创建一个新的对象，而不仅仅是一个对原有对象的引用。为了防止这种情况，可以在单例类中加入</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">readResolve</span>
				<span style="font-family: 宋体;">方法。</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: 宋体;">关于这个方法的具体情况请参考《</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: 'Comic Sans MS';" lang="EN-US">Effective Java</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: 宋体;">》一书第</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: 'Comic Sans MS';" lang="EN-US">57</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: 宋体;">条建议。</span>
				<span style="font-family: 'Comic Sans MS';">
						<span lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">其实对象的串行化并不仅局限于上述方式，还存在基于</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">XML</span>
				<span style="font-family: 宋体;">格式的对象串行化方式。这种方式也存在上述的问题，所以在使用的时候要格外小心。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">上面罗列了一些使用单例模式时可能会遇到的问题。而且这些问题都和</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">java</span>
				<span style="font-family: 宋体;">中的类、线程、虚拟机等基础而又复杂的概念交织在一起，你如果稍不留神……。但是这并不代表着单例模式就一无是处，更不能一棒子将其打死。它还是不可缺少的一种基础设计模式，它对一些问题提供了非常有效的解决方案，在</span>
				<span lang="EN-US">java</span>
				<span style="font-family: 宋体;">中你完全可以把它看成编码规范来学习，只是使用的时候要考虑周全些就可以了。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">五、</span>
				</span>
				<span style="font-family: 宋体;">题外话</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">抛开单例模式，使用下面一种简单的方式也能得到单例，而且如果你确信此类永远是单例的，使用下面这种方式也许更好一些。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">public static final Singleton INSTANCE = new Singleton();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">而使用单例模式提供的方式，这可以在不改变</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">API</span>
				<span style="font-family: 宋体;">的情况下，改变我们对单例类的具体要求。</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<span style="">六、</span>
				</span>
				<span style="font-family: 宋体;">总结</span>
				<span style="font-family: 'Comic Sans MS';" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<span style="font-family: 宋体;">竭尽所能写下了关于单例模式比较详细的介绍，请大家指正。</span>
<img src ="http://www.blogjava.net/alex/aggbug/66499.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 19:05 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66499.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出装饰模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66497.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 10:57:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66497.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66497.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66497.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66497.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66497.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">一、引子</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">装饰模式？肯定让你想起又黑又火的家庭装修来。其实两者在道理上还是有很多相像的地方。家庭装修无非就是要掩盖住原来实而不华的墙面，抹上一层华而不实的涂料，让生活多一点色彩。而墙还是那堵墙，他的本质一点都没有变，只是多了一层外衣而已。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">那设计模式中的装饰模式，是什么样子呢？</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">二、定义与结构</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">装饰模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Decorator</span>
						<span style="font-family: 宋体;">）也叫包装器模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Wrapper</span>
						<span style="font-family: 宋体;">）。</span>
						<span style="font-family: Tahoma;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">在《设计模式》一书中给出的定义为：动态地给一个对象添加一些额外的职责。就增加功能来说，</span>
						<span style="font-family: Tahoma;" lang="EN-US">Decorator</span>
						<span style="font-family: 宋体;">模式相比生成子类更为灵活。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">让我们来理解一下这句话。我们来设计</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">门</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">这个类。假设你根据需求为</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">门</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">类作了如下定义：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<p>
										<img src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_door.jpg" alt="" align="middle" />
								</p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
								<stroke joinstyle="miter">
								</stroke>
								<formulas>
										<f eqn="if lineDrawn pixelLineWidth 0">
										</f>
										<f eqn="sum @0 1 0">
										</f>
										<f eqn="sum 0 0 @1">
										</f>
										<f eqn="prod @2 1 2">
										</f>
										<f eqn="prod @3 21600 pixelWidth">
										</f>
										<f eqn="prod @3 21600 pixelHeight">
										</f>
										<f eqn="sum @0 0 1">
										</f>
										<f eqn="prod @6 1 2">
										</f>
										<f eqn="prod @7 21600 pixelWidth">
										</f>
										<f eqn="sum @8 21600 0">
										</f>
										<f eqn="prod @7 21600 pixelHeight">
										</f>
										<f eqn="sum @10 21600 0">
										</f>
								</formulas>
								<path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect">
								</path>
								<lock v:ext="edit" aspectratio="t">
								</lock>
						</shapetype>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">现在，在系统的一个地方需要一个能够报警的</span>
						<span style="font-family: Tahoma;" lang="EN-US">Door</span>
						<span style="font-family: 宋体;">，你来怎么做呢？你或许写一个</span>
						<span style="font-family: Tahoma;" lang="EN-US">Door</span>
						<span style="font-family: 宋体;">的子类</span>
						<span style="font-family: Tahoma;" lang="EN-US">AlarmDoor</span>
						<span style="font-family: 宋体;">，在里面添加一个子类独有的方法</span>
						<span style="font-family: Tahoma;" lang="EN-US">alarm()</span>
						<span style="font-family: 宋体;">。嗯，那在使用警报门的地方你必须让客户知道使用的是警报门，不然无法使用这个独有的方法。而且，这个还违反了</span>
						<span style="font-family: Tahoma;" lang="EN-US">Liskov</span>
						<span style="font-family: 宋体;">替换原则。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">也许你要说，那就把这个方法添加到</span>
						<span style="font-family: Tahoma;" lang="EN-US">Door</span>
						<span style="font-family: 宋体;">里面，这样不就统一了？但是这样所有的门都必须有警报，至少是个</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">哑巴</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">警报。而当你的系统仅仅在一两个地方使用了警报门，这明显是不合理的</span>
						<span style="font-family: Tahoma;" lang="EN-US">——</span>
						<span style="font-family: 宋体;">虽然可以使用缺省适配器来弥补一下。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">这时候，你可以考虑采用装饰模式来给门动态的添加些额外的功能。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">下面我们来看看装饰模式的组成，不要急着去解决上面的问题，到了下面自然就明白了！</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象构件角色（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Component</span>
						<span style="font-family: 宋体;">）：定义一个抽象接口，以规范准备接收附加责任的对象。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体构件角色</span>
						<span style="font-family: Tahoma;" lang="EN-US">(Concrete Component)</span>
						<span style="font-family: 宋体;">：这是被装饰者，定义一个将要被装饰增加功能的类。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">3)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">装饰角色</span>
						<span style="font-family: Tahoma;" lang="EN-US">(Decorator)</span>
						<span style="font-family: 宋体;">：持有一个构件对象的实例，并定义了抽象构件定义的接口。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">4)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体装饰角色</span>
						<span style="font-family: Tahoma;" lang="EN-US">(Concrete Decorator)</span>
						<span style="font-family: 宋体;">：负责给构件添加增加的功能。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">看下装饰模式的类图：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
								<img src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_decorator.jpg" alt="" align="middle" />
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">图中</span>
						<span style="font-family: Tahoma;" lang="EN-US">ConcreteComponent</span>
						<span style="font-family: 宋体;">可能继承自其它的体系，而为了实现装饰模式，他还要实现</span>
						<span style="font-family: Tahoma;" lang="EN-US">Component</span>
						<span style="font-family: 宋体;">接口。整个装饰模式的结构是按照组合模式来实现的，但是注意两者的目的是截然不同的（关于两者的不同请关注我以后的文章）。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">三、举例</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">这个例子还是来自我最近在研究的</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">，如果你对</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">还不太了解，可以参考</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<a href="http://blog.csdn.net/ai92/archive/2005/02/26/302844.aspx">
										<span style="font-family: 宋体;" lang="EN-US">
												<span lang="EN-US">《</span>
										</span>JUnit<span style="font-family: 宋体;" lang="EN-US"><span lang="EN-US">入门》</span></span></a>
						</span>
						<span style="font-family: 宋体;">、</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<a href="http://blog.csdn.net/ai92/archive/2005/03/12/318318.aspx">
										<span style="font-family: 宋体;" lang="EN-US">
												<span lang="EN-US">《</span>
										</span>JUnit<span style="font-family: 宋体;" lang="EN-US"><span lang="EN-US">源码分析（一）》</span></span></a>
						</span>
						<span style="font-family: 宋体;">、</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<a href="http://blog.csdn.net/ai92/archive/2005/03/13/318878.aspx">
										<span style="font-family: 宋体;" lang="EN-US">
												<span lang="EN-US">《</span>
										</span>JUnit<span style="font-family: 宋体;" lang="EN-US"><span lang="EN-US">源码分析（二）》</span></span></a>
						</span>
						<span style="font-family: 宋体;">、</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<a href="http://blog.csdn.net/ai92/archive/2005/03/14/319352.aspx">
										<span style="font-family: 宋体;" lang="EN-US">
												<span lang="EN-US">《</span>
										</span>JUnit<span style="font-family: 宋体;" lang="EN-US"><span lang="EN-US">源码分析（三）》</span></span></a>
						</span>
						<span style="font-family: 宋体;">。不愧是由</span>
						<span style="font-family: Tahoma;" lang="EN-US">GoF</span>
						<span style="font-family: 宋体;">之一的</span>
						<span style="font-family: Tahoma;" lang="EN-US">Erich Gamma</span>
						<span style="font-family: 宋体;">亲自开发的，小小的东西使用了</span>
						<span style="font-family: Tahoma;" lang="EN-US">N</span>
						<span style="font-family: 宋体;">种的模式在里面。下面就来看看</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">中的装饰模式。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">在</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">中，</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestCase</span>
						<span style="font-family: 宋体;">是一个很重要的类，允许对其进行功能扩展。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">在</span>
						<span style="font-family: Tahoma;" lang="EN-US">junit.extensions</span>
						<span style="font-family: 宋体;">包中，</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestDecorator</span>
						<span style="font-family: 宋体;">、</span>
						<span style="font-family: Tahoma;" lang="EN-US">RepeatedTest</span>
						<span style="font-family: 宋体;">便是对</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestCase</span>
						<span style="font-family: 宋体;">的装饰模式扩展。下面我们将它们和上面的角色对号入座。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">
								<img src="http://blog.csdn.net/images/blog_csdn_net/ai92/85479/r_test.jpg" alt="" align="middle" />
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">呵呵，看看源代码吧，这个来的最直接！</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>//</span>
						<span style="font-family: 宋体;">这个就是抽象构件角色</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public interface Test {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* Counts the number of test cases that will be run by this test.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public abstract int countTestCases();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* Runs a test and collects its result in a TestResult instance.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public abstract void run(TestResult result);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">具体构件对象，但是这里是个抽象类</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public abstract class TestCase extends Assert implements Test {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>……</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public int countTestCases() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>return 1;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>……</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public TestResult run() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>TestResult result= createResult();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>run(result);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>return result;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void run(TestResult result) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>result.run(this);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>……</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">装饰角色</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class TestDecorator extends Assert implements Test {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>//</span>
						<span style="font-family: 宋体;">这里按照上面的要求，保留了一个对构件对象的实例</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>protected Test fTest;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public TestDecorator(Test test) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>fTest= test;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* The basic run behaviour.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void basicRun(TestResult result) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>fTest.run(result);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public int countTestCases() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>return fTest.countTestCases();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void run(TestResult result) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>basicRun(result);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public String toString() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>return fTest.toString();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public Test getTest() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>return fTest;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>//</span>
						<span style="font-family: 宋体;">具体装饰角色，这个类的增强作用就是可以设置测试类的执行次数</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class RepeatedTest extends<span style="">  </span>TestDecorator {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>private int fTimesRepeat;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>public RepeatedTest(Test test, int repeat) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">           </span>super(test);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">           </span>if (repeat &lt; 0)</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                  </span>throw new IllegalArgumentException("Repetition count must be &gt; 0");</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">           </span>fTimesRepeat= repeat;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">    </span>//</span>
						<span style="font-family: 宋体;">看看怎么装饰的吧</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>public int countTestCases() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">           </span>return super.countTestCases()*fTimesRepeat;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>public void run(TestResult result) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">           </span>for (int i= 0; i &lt; fTimesRepeat; i++) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                  </span>if (result.shouldStop())</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                         </span>break;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                  </span>super.run(result);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">           </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>public String toString() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">           </span>return super.toString()+"(repeated)";</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">    </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 10.5pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">使用的时候，就可以采用下面的方式：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">TestDecorator test = new RepeatedTest(new TestXXX() , 3);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">让我们在回想下上面提到的</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">门</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">的问题，这个警报门采用了装饰模式后，可以采用下面的方式来产生。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">DoorDecorator alarmDoor = new AlarmDoor(new Door());</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">四、应用环境</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>GOF</span>
						<span style="font-family: 宋体;">书中给出了以下使用情况：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">在不影响其他对象的情况下，以动态、透明的方式给单个对象添加职责。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">处理那些可以撤消的职责。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">3)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">当不能采用生成子类的方法进行扩充时。一种情况是，可能有大量独立的扩展，为支持每一种组合将产生大量的子类，使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏，或类定义不能用于生成子类。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">来分析下</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">的使用是属于哪种情况。首先实现了比静态继承更加灵活的方式，动态的增加功能。试想为</span>
						<span style="font-family: Tahoma;" lang="EN-US">Test</span>
						<span style="font-family: 宋体;">的所有实现类通过继承来增加一个功能，意味着要添加不少的功能类似的子类，这明显是不太合适的。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">而且，这就避免了高层的类具有太多的特征，比如上面提到的带有警报的抽象门类。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">五、透明和半透明</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">对于面向接口编程，应该尽量使客户程序不知道具体的类型，而应该对一个接口操作。这样就要求装饰角色和具体装饰角色要满足</span>
						<span style="font-family: Tahoma;" lang="EN-US">Liskov</span>
						<span style="font-family: 宋体;">替换原则。像下面这样：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">Component c = new ConcreteComponent();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">Component c1 = new ConcreteDecorator(c);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">中就属于这种应用，这种方式被称为透明式。而在实际应用中，比如</span>
						<span style="font-family: Tahoma;" lang="EN-US">java.io</span>
						<span style="font-family: 宋体;">中往往因为要对原有接口做太多的扩展而需要公开新的方法（这也是为了重用）。所以往往不能对客户程序隐瞒具体的类型。这种方式称为</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">半透明式</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: 宋体;">在</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: Tahoma;" lang="EN-US">java.io</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: 宋体;">中，并不是纯装饰模式的范例，它是装饰模式、适配器模式的混合使用。</span>
				<span style="font-size: 9pt; color: rgb(51, 51, 51); font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">六、其它</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">采用</span>
						<span style="font-family: Tahoma;" lang="EN-US">Decorator</span>
						<span style="font-family: 宋体;">模式进行系统设计往往会产生许多看上去类似的小对象，这些对象仅仅在他们相互连接的方式上有所不同，而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说，很容易对它们进行定制，但是很难学习这些系统，排错也很困难。这是</span>
						<span style="font-family: Tahoma;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">提到的装饰模式的缺点，你能体会吗？他们所说的小对象我认为是指的具体装饰角色。这是为一个对象动态添加功能所带来的副作用。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">七、总结</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<font size="3">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">       </span>
				</span>
				<span style="font-family: 宋体;">终于写完了，不知道说出了本意没有。请指正！</span>
		</font>
<img src ="http://www.blogjava.net/alex/aggbug/66497.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 18:57 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66497.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出观察者模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66488.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 10:08:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66488.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66488.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66488.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66488.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66488.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="" lang="EN-US">
								<span style="">
										<font face="Times New Roman">一、</font>
								</span>
						</span>
						<span style="font-family: 宋体;">引子</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">还记得警匪片上，匪徒们是怎么配合实施犯罪的吗？一个团伙在进行盗窃的时候，总</span>
						<span lang="EN-US">
								<span style="">
										<font face="Times New Roman">    </font>
								</span>
						</span>
						<span style="font-family: 宋体;">有一两个人在门口把风——如果有什么风吹草动，则会立即通知里面的同伙紧急撤退。也许放风的人并不一定认识里面的每一个同伙；而在里面也许有新来的小弟不认识这个放风的。但是这没什么，这个影响不了他们之间的通讯，因为他们之间有早已商定好的暗号。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">呵呵，上面提到的放风者、偷窃者之间的关系就是观察者模式在现实中的活生生的例子。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<p>
								<font face="Times New Roman" size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">二、</span>
						</span>
						<span style="font-family: 宋体;">定义与结构</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">观察者（</span>
						<span lang="EN-US">
								<font face="Times New Roman">Observer</font>
						</span>
						<span style="font-family: 宋体;">）模式又名发布</span>
						<span lang="EN-US">
								<font face="Times New Roman">-</font>
						</span>
						<span style="font-family: 宋体;">订阅（</span>
						<span lang="EN-US">
								<font face="Times New Roman">Publish/Subscribe</font>
						</span>
						<span style="font-family: 宋体;">）模式。</span>
						<span lang="EN-US">
								<font face="Times New Roman">GOF</font>
						</span>
						<span style="font-family: 宋体;">给观察者模式如下定义：定义对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">在这里先讲一下面向对象设计的一个重要原则——单一职责原则。因此系统的每个对象应该将重点放在问题域中的离散抽象上。因此理想的情况下，一个对象只做一件事情。这样在开发中也就带来了诸多的好处：提供了重用性和维护性，也是进行重构的良好的基础。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">因此几乎所有的设计模式都是基于这个基本的设计原则来的。观察者模式的起源我觉得应该是在</span>
						<span style="font-family: Tahoma;" lang="EN-US">GUI</span>
						<span style="font-family: 宋体;">和业务数据的处理上，因为现在绝大多数讲解观察者模式的例子都是这一题材。但是观察者模式的应用决不仅限于此一方面。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">下面我们就来看看观察者模式的组成部分。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">1)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象目标角色（</span>
						<span lang="EN-US">
								<font face="Times New Roman">Subject</font>
						</span>
						<span style="font-family: 宋体;">）：目标角色知道它的观察者，可以有任意多个观察者观察同一个目标。并且提供注册和删除观察者对象的接口。目标角色往往由抽象类或者接口来实现。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">2)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象观察者角色（</span>
						<span lang="EN-US">
								<font face="Times New Roman">Observer</font>
						</span>
						<span style="font-family: 宋体;">）：为那些在目标发生改变时需要获得通知的对象定义一个更新接口。抽象观察者角色主要由抽象类或者接口来实现。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">3)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体目标角色（</span>
						<span lang="EN-US">
								<font face="Times New Roman">Concrete Subject</font>
						</span>
						<span style="font-family: 宋体;">）：将有关状态存入各个</span>
						<span lang="EN-US">
								<font face="Times New Roman">Concrete Observer</font>
						</span>
						<span style="font-family: 宋体;">对象。当它的状态发生改变时</span>
						<span lang="EN-US">
								<font face="Times New Roman">, </font>
						</span>
						<span style="font-family: 宋体;">向它的各个观察者发出通知。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">4)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体观察者角色（</span>
						<span lang="EN-US">
								<font face="Times New Roman">Concrete Observer</font>
						</span>
						<span style="font-family: 宋体;">）：存储有关状态，这些状态应与目标的状态保持一致。实现</span>
						<span lang="EN-US">
								<font face="Times New Roman">Observer</font>
						</span>
						<span style="font-family: 宋体;">的更新接口以使自身状态与目标的状态保持一致。在本角色内也可以维护一个指向</span>
						<span lang="EN-US">
								<font face="Times New Roman">Concrete Subject</font>
						</span>
						<span style="font-family: 宋体;">对象的引用。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">放上观察者模式的类图，这样能将关系清晰的表达出来。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
								<img src="http://blog.csdn.net/images/blog_csdn_net/ai92/105445/r_observer.jpg" alt="" />
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-align: center;" align="center">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
										<stroke joinstyle="miter">
										</stroke>
										<formulas>
												<f eqn="if lineDrawn pixelLineWidth 0">
												</f>
												<f eqn="sum @0 1 0">
												</f>
												<f eqn="sum 0 0 @1">
												</f>
												<f eqn="prod @2 1 2">
												</f>
												<f eqn="prod @3 21600 pixelWidth">
												</f>
												<f eqn="prod @3 21600 pixelHeight">
												</f>
												<f eqn="sum @0 0 1">
												</f>
												<f eqn="prod @6 1 2">
												</f>
												<f eqn="prod @7 21600 pixelWidth">
												</f>
												<f eqn="sum @8 21600 0">
												</f>
												<f eqn="prod @7 21600 pixelHeight">
												</f>
												<f eqn="sum @10 21600 0">
												</f>
										</formulas>
										<path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
										</path>
										<lock aspectratio="t" v:ext="edit">
										</lock>
								</shapetype>
								<shape id="_x0000_i1025" style="width: 309pt; height: 207pt;" type="#_x0000_t75">
										<imagedata o:title="" src="file:///C:%5CDOCUME%7E1%5CAI92%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.emz">
										</imagedata>
								</shape>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">可以看得出来，在</span>
						<span style="font-family: Tahoma;" lang="EN-US">Subject</span>
						<span style="font-family: 宋体;">这个抽象类中，提供了上面提到的功能，而且存在一个通知方法：</span>
						<span style="font-family: Tahoma;" lang="EN-US">notify</span>
						<span style="font-family: 宋体;">。还可以看出来</span>
						<span style="font-family: Tahoma;" lang="EN-US">Subject</span>
						<span style="font-family: 宋体;">和</span>
						<span style="font-family: Tahoma;" lang="EN-US">ConcreteSubject</span>
						<span style="font-family: 宋体;">之间可以说是使用了模板模式（这个模式真是简单普遍到一不小心就用到了）。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">这样当具体目标角色的状态发生改变，按照约定则会去调用通知方法，在这个方法中则会根据目标角色中注册的观察者名单来逐个调用相应的</span>
						<span style="font-family: Tahoma;" lang="EN-US">update</span>
						<span style="font-family: 宋体;">方法来调整观察者的状态。这样观察者模式就走完了一个流程。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">在下面的例子中会更深刻的体验到这个流程的。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">三、</span>
						</span>
						<span style="font-family: 宋体;">举例</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">观察者模式是我在《</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">源代码分析》中遗留的一个模式，因此这里将采用</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">来作为例子。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">为用户提供了三种不同的测试结果显示界面，以后还可能会有其它方式的现实界面……。怎么才能将测试的业务逻辑和显示结果的界面很好的分离开？不用问，就是观察者模式！</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">下面我们来看看</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">中观察者模式的使用代码：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">下面是我们的抽象观察者角色，</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">是采用接口来实现的，这也是一般采用的方式。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">可以看到这里面定义了四个不同的</span>
						<span style="font-family: Tahoma;" lang="EN-US">update</span>
						<span style="font-family: 宋体;">方法，对应四种不同的状态变化</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public interface TestListener {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style=""> </span>
								<span style="">     </span>
								<span style=""> </span>* An error occurred.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style=""> </span>
								<span style="">     </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void addError(Test test, Throwable t);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style=""> </span>
								<span style="">     </span>
								<span style=""> </span>* A failure occurred.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style=""> </span>
								<span style="">     </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style=""> </span>
								<span style="">     </span>public void addFailure(Test test, AssertionFailedError t);<span style="">  </span></font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* A test ended.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style=""> </span>
								<span style="">     </span>public void endTest(Test test); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* A test started.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void startTest(Test test);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">具体观察者角色，我们采用最简单的</span>
						<span style="font-family: Tahoma;" lang="EN-US">TextUI</span>
						<span style="font-family: 宋体;">下的情况来说明（</span>
						<span style="font-family: Tahoma;" lang="EN-US">AWT</span>
						<span style="font-family: 宋体;">，</span>
						<span style="font-family: Tahoma;" lang="EN-US">Swing</span>
						<span style="font-family: 宋体;">对于整天做</span>
						<span style="font-family: Tahoma;" lang="EN-US">Web</span>
						<span style="font-family: 宋体;">应用的人来说，已经很陌生了）</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class ResultPrinter implements TestListener {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>//</span>
						<span style="font-family: 宋体;">省略好多啊，主要是显示代码</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<font face="Times New Roman">
						<font size="3">
								<span style="" lang="EN-US">……</span>
								<span style="font-family: Tahoma;" lang="EN-US">
								</span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>//</span>
						<span style="font-family: 宋体;">下面就是实现接口</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestListener</span>
						<span style="font-family: 宋体;">的四个方法</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>//</span>
						<span style="font-family: 宋体;">填充方法的行为很简单的说</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* @see junit.framework.TestListener#addError(Test, Throwable)</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void addError(Test test, Throwable t) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>getWriter().print("E");</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void addFailure(Test test, AssertionFailedError t) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>getWriter().print("F");</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* @see junit.framework.TestListener#endTest(Test)</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void endTest(Test test) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* @see junit.framework.TestListener#startTest(Test)</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public void startTest(Test test) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>getWriter().print(".");</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>if (fColumn++ &gt;= 40) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                     </span>getWriter().println();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                     </span>fColumn= 0;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">来看下我们的目标角色，随便说下，由于</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">功能的简单，只有一个目标——</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestResult</span>
						<span style="font-family: 宋体;">，因此</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">只有一个具体目标角色。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">好长的代码，好像没有重点。去掉了大部分与主题无关的信息</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">下面只列出了当</span>
						<span style="font-family: Tahoma;" lang="EN-US">Failures</span>
						<span style="font-family: 宋体;">发生时是怎么来通知观察者的</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class TestResult extends Object {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>//</span>
						<span style="font-family: 宋体;">这个是用来存放测试</span>
						<span style="font-family: Tahoma;" lang="EN-US">Failures</span>
						<span style="font-family: 宋体;">的集合</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 42pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">protected Vector fFailures;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 42pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">这个就是用来存放注册进来的观察者的集合</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>protected Vector fListeners;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public TestResult() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>fFailures= new Vector();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>fListeners= new Vector();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* Adds a failure to the list of failures. The passed in exception</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>* caused the failure.</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public synchronized void addFailure(Test test, AssertionFailedError t) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>fFailures.addElement(new TestFailure(test, t));</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">              </span>//</span>
						<span style="font-family: 宋体;">下面就是通知各个观察者的</span>
						<span style="font-family: Tahoma;" lang="EN-US">addFailure</span>
						<span style="font-family: 宋体;">方法</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                     </span>((TestListener)e.nextElement()).addFailure(test, t);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
								<span style=""> </span>* </span>
						<span style="font-family: 宋体;">注册一个观察者</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public synchronized void addListener(TestListener listener) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>fListeners.addElement(listener);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
								<span style=""> </span>* </span>
						<span style="font-family: 宋体;">删除一个观察者</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public synchronized void removeListener(TestListener listener) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>fListeners.removeElement(listener);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>/**</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
								<span style=""> </span>* </span>
						<span style="font-family: 宋体;">返回一个观察者集合的拷贝，当然是为了防止对观察者集合的非法方式操作了</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">     </span>* </span>
						<span style="font-family: 宋体;">可以看到所有使用观察者集合的地方都通过它</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style=""> </span>*/</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>private synchronized Vector cloneListeners() {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>return (Vector)fListeners.clone();</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<font face="Times New Roman">
								<span style="" lang="EN-US">……</span>
								<span style="font-family: Tahoma;" lang="EN-US">
								</span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">嗯，观察者模式组成所需要的角色在这里已经全了。不过好像还是缺点什么……。呵呵，对！就是它们之间还没有真正的建立联系。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">JUnit</span>
						<span style="font-family: 宋体;">中是通过</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestRunner</span>
						<span style="font-family: 宋体;">来作的，而你在具体的系统中可以灵活掌握。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">看一下</span>
						<span style="font-family: Tahoma;" lang="EN-US">TestRunner</span>
						<span style="font-family: 宋体;">中的代码：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class TestRunner extends BaseTestRunner {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>private ResultPrinter fPrinter;</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public TestResult doRun(Test suite, boolean wait) {</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">就是在这里注册的</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>result.addListener(fPrinter);</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<font face="Times New Roman">
						<font size="3">
								<span style="" lang="EN-US">……</span>
								<span style="font-family: Tahoma;" lang="EN-US">
								</span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">四、</span>
						</span>
						<span style="font-family: 宋体;">使用情况</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span lang="EN-US">
								<font face="Times New Roman">GOF</font>
						</span>
						<span style="font-family: 宋体;">给出了以下使用观察者模式的情况：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">1)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">当一个抽象模型有两个方面</span>
						<span lang="EN-US">
								<font face="Times New Roman">, </font>
						</span>
						<span style="font-family: 宋体;">其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">2)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">当对一个对象的改变需要同时改变其它对象</span>
						<span lang="EN-US">
								<font face="Times New Roman">, </font>
						</span>
						<span style="font-family: 宋体;">而不知道具体有多少对象有待改变。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">
										<font size="3">3)</font>
										<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
								</font>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">当一个对象必须通知其它对象，而它又不能假定其它对象是谁。换言之</span>
						<span lang="EN-US">
								<font face="Times New Roman">, </font>
						</span>
						<span style="font-family: 宋体;">你不希望这些对象是紧密耦合的。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">其实观察者模式同前面讲过的桥梁、策略有着共同的使用环境：将变化独立封装起来，以达到最大的重用和解耦。观察者与后两者不同的地方在于，观察者模式中的目标和观察者的变化不是独立的，而是有着某些联系。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">五、</span>
						</span>
						<span style="font-family: 宋体;">我推你拉</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">观
察者模式在关于目标角色、观察者角色通信的具体实现中，有两个版本。一种情况便是目标角色在发生变化后，仅仅告诉观察者角色“我变化了”；观察者角色如果
想要知道具体的变化细节，则就要自己从目标角色的接口中得到。这种模式被很形象的称为：拉模式——就是说变化的信息是观察者角色主动从目标角色中“拉”出
来的。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">还有一种方法，那就是我目标角色“服务一条龙”，通知你发生变化的同时，通过一个参数将变化的细节传递到观察者角色中去。这就是“推模式”——管你要不要，先给你啦。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">这两种模式的使用，取决于系统设计时的需要。如果目标角色比较复杂，并且观察者角色进行更新时必须得到一些具体变化的信息，则“推模式”比较合适。如果目标角色比较简单，则“拉模式”就很合适啦。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">六、</span>
						</span>
						<span style="font-family: 宋体;">总结</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">大概的介绍了下观察者模式。希望能对你有所帮助。</font>
				</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66488.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 18:08 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66488.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]由表及里看模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66486.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 09:56:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66486.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66486.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66486.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66486.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66486.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">一、</span>
						</span>
						<span style="font-family: 宋体;">引子</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">记得一年前，我开始陆陆续续在自己的</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<a href="http://blog.csdn.net/ai92">blog</a>
						</span>
						<span style="font-family: 宋体;">上连载《深入浅出设计模式》。其内容无出经典巨著《设计模式》之右，仅仅偶有己见，但是它记录了我学习、思考和讲述设计模式的过程。一晃，距离写成最后一片设计模式的文章已有</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">3</span>
						<span style="font-family: 宋体;">月余，我却迟迟没有对设计模式做一个总结。心想，总不能虎头蛇尾吧，于是便有了这篇文章。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">二、</span>
						</span>
						<span style="font-family: 宋体;">回顾</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种设计模式</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">先来回顾下这</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种经典的设计模式吧，下图给出了</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">对它们的分类：</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> <img src="http://blog.csdn.net/images/blog_csdn_net/ai92/105445/r_23GOFP1.JPG" alt="" /></font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
										<stroke joinstyle="miter">
										</stroke>
										<formulas>
												<f eqn="if lineDrawn pixelLineWidth 0">
												</f>
												<f eqn="sum @0 1 0">
												</f>
												<f eqn="sum 0 0 @1">
												</f>
												<f eqn="prod @2 1 2">
												</f>
												<f eqn="prod @3 21600 pixelWidth">
												</f>
												<f eqn="prod @3 21600 pixelHeight">
												</f>
												<f eqn="sum @0 0 1">
												</f>
												<f eqn="prod @6 1 2">
												</f>
												<f eqn="prod @7 21600 pixelWidth">
												</f>
												<f eqn="sum @8 21600 0">
												</f>
												<f eqn="prod @7 21600 pixelHeight">
												</f>
												<f eqn="sum @10 21600 0">
												</f>
										</formulas>
										<path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
										</path>
										<lock aspectratio="t" v:ext="edit">
										</lock>
								</shapetype>
								<shape id="_x0000_i1025" style="width: 415.5pt; height: 174.75pt;" type="#_x0000_t75">
										<imagedata o:title="" src="file:///C:%5CDOCUME%7E1%5CAi92%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.emz">
										</imagedata>
								</shape>
						</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<font size="3">
								<span style="">    </span>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">    </span>
						</span>
						<span style="font-family: 宋体;">图中从两个纬度将</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种设计模式划分为六大类：创建型类模式、创建型对象模式、结构型类模式、结构型对象模式、行为型类模式、行为型对象模式。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">对这</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种模式的划分是有一定道理的，虽然人为的类型划分，说到底还是有些牵强，但是如</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">所说，它至少可以帮助记忆学习。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">    </span>
						</span>
						<span style="font-family: 宋体;">被分为六大块的</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种设计模式并不是割裂开来的，很多模式的使用往往是相生相伴的，像工厂与单例，装饰与组合等等。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">给出了模式间的关系详细描述如下图：</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> <img src="http://blog.csdn.net/images/blog_csdn_net/ai92/105445/r_23GOFP2.JPG" alt="" /></font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<shape id="_x0000_i1026" style="width: 414.75pt; height: 458.25pt;" type="#_x0000_t75">
										<imagedata o:title="" src="file:///C:%5CDOCUME%7E1%5CAi92%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_image003.emz" cropbottom="3108f">
										</imagedata>
								</shape>
						</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<font size="3">
								<span style="">    </span>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">    </span>
						</span>
						<span style="font-family: 宋体;">记得曾经不止一次有人问我：这模式和那模式感觉上一样啊，有什么区别啊。同样，在很多论坛上也充满了这样的疑问。其实这是很正常的，面向对象设计、编程所能使用的方式不外乎这几种：继承、组合、封装行为、利用多态等等，所以</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种模式中翻来覆去的使用这几种方式，看起来当然是似曾相逢。有人曾留言给我，让我着重表述这些模式之间的区别与类似。我当时也许诺会在最后写一篇总结性的文章专门讨论这个话题，但是现在我不打算这样干了。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">三、俯瞰全局、</span>
						<span style="font-family: 宋体;">追踪溯源</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">    </span>
						</span>
						<span style="font-family: 宋体;">什么是设计模式？</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">在书中如是说：</span>
						<span style="font-family: 宋体;">设计模式是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述；</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">John Vlissides</span>
						<span style="font-family: 宋体;">曾说过：<font color="#ff0000">在设计模式中，仅有的、最重要的就是不断的反省；而我将它比作软件开发中经验积累出来的“公式”。</font></span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">    </span>
						</span>
						<span style="font-family: 宋体;">通看这</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种模式，就应了</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">Dennis DeBruler</span>
						<span style="font-family: 宋体;">曾说过的一句话：<font color="#ff0000">计算机科学是一门相信所有问题都可以通过多一个<strike><b>间接层</b></strike>（</font></span>
						<font color="#ff0000">
								<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">indirection</span>
						</font>
						<span style="font-family: 宋体;">
								<font color="#ff0000">）来解决的科学。</font>在前面关于具体模式的文章中，我曾经不只一次的提到“中间层”。但是直到读到这句话，才使我跳出具体模式的束缚俯瞰全局。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">    </span>23</span>
						<span style="font-family: 宋体;">种模式似乎不再神奇，它们在解决问题上的思路是如此的相似——添加间接层。何止模式如此，正如</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">Dennis DeBruler</span>
						<span style="font-family: 宋体;">所言，我们所接触的很多技术都是采用这种手段，如：</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">J2EE</span>
						<span style="font-family: 宋体;">的分层技术、重构等等。但是在具体操作上，</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种模式中间接层的应用可大可小，无比灵活。观察者模式在动作触发端与动作执行端之间加入了目标角色层，解除了两端之间的耦合，巧妙地解决了一对多的关系；单例模式将构造方法私有化，并在使用者与构造方法之间添加一个获得唯一实例的静态方法，达到控制实例个数的目的。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">    </span>
						</span>
						<span style="font-family: 宋体;">间接层应用如此广泛，得益于它能带来如下好处：共享逻辑（重用）、分离意图和实现（提高灵活性）、</span>
						<span style="font-family: &quot;Courier New&quot;;">
						</span>
						<span style="font-family: 宋体;">隔
离变化（封装）、解耦等等。既然我们知道了间接层这么一回事，似乎我们可以不用知道设计模式也能做出像设计模式那样好的设计来。但是要记住，间接层应用过
于泛滥，则会过犹不及，它会导致简单问题复杂化、跳跃阅读难以理解等问题。那如何在设计中把握使用间接层的度呢？设计模式也许是很好的范例——你毕竟是站
在了巨人的肩上。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<font size="3">
								<span style="">    </span>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">再深入一层细看，在设计模式中，<font color="#ff0000">广泛遵循了两条设计原则：面向接口编程，而不是实现；优先使用组合，而不是继承。</font>这两条原则带来的好处，自然不用再说了。说到设计原则，</span>
						<span style="font-family: 宋体;">现在为人熟知的设计原则有很多，如：</span>
						<span style="font-family: 宋体;">单一职责原则（</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">SRP</span>
						<span style="font-family: 宋体;">）、开闭原则（</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">OCP</span>
						<span style="font-family: 宋体;">）、</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">Liskov</span>
						<span style="font-family: 宋体;">替换原则（</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">LSP</span>
						<span style="font-family: 宋体;">）、依赖倒置原则（</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">DIP</span>
						<span style="font-family: 宋体;">）和接口隔离原则（</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">ISP</span>
						<span style="font-family: 宋体;">）等等。这些原则的出现大多都早于设计模式，但同设计模式一样，是</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">OOD</span>
						<span style="font-family: 宋体;">过程中经验积累的结晶。它们在</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种设计模式中都有体现，因此了解设计原则可以帮助你更好的分析和理解设计模式。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">当然，这并不是说设计模式就是建立在设计原则的基础之上的。两者之间的关系是互相促进的。设计原则的诞生，也许会促成新的设计模式；设计模式的出现，也许会提炼出新的设计原则。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">现在不禁要问，为什么使用设计模式。也许你的回答会是：提高设计的重用度、灵活性、可维护性等等。但是我认为更准确的回答应该是：解决系统设计中现有的问题。这便又回到了</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">给设计模式下的定义上了，绕了一个圈子，原来答案就这么简单。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">这也就是我不想详细讲解各种模式区别的原因了，要解决的问题不一样就是它们之间最大的不同。如果还要详细分析，那它们都已写在</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">巨著中了——就是它们的定义、使用范围、优缺点等等。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">四、</span>
						</span>
						<span style="font-family: 宋体;">活学活用</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">是否我们必须按照这本巨著上描述的形式来使用设计模式呢？肯定不是这样的。数学物理公式在不同的条件下还会有不同的衍生式，何况这些在实践中总结的经验呢。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">Martin</span>
						<span style="font-family: 宋体;">建
议根据问题的复杂性逐步的引入设计模式。这是个很好的建议，它避免你套用模式而带来了过度的设计，而这些过度的设计也许直到最后都派不上用场。比如，你的
系统中现在就仅有一个适配器角色，或者各个适配器角色没有什么共性，那么目标角色和适配器角色就可以合为一个，这样使得设计模式更加符合你系统的特性。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">不
仅如此，做到设计模式的活学活用，<font color="#ff0000">我认为还要做到以解决问题为中心，将设计模式融合使用，避免为了设计而模式</font>。当然这是建立在对各种设计模式了如指掌的情
况下。比如，有一段解析字符串的对象，而在使用它之前，还要做一些参数的判断等其他非解析操作，这时，你很快就会想起使用代理模式；但是这个代理提供的接
口可能有两三个（满足不同情形），而解析对象仅有一个接口，命名还不相同，这时你又想到了适配器模式。这时也许将两者融合成你独有的解决方案比笨拙的套用
两个模式好的多得多。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">五、现在看模式</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">说过，这</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种模式仅仅是对一般设计问题的总结。现在许多专有领域也开始出现了大量的设计模式，至少在我最了解的企业应用这个方向是这样的。其中有一部分模式仅仅是对</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">设计模式的再次包装。我们不妨叫</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
						<span style="font-family: 宋体;">的</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">23</span>
						<span style="font-family: 宋体;">种设计模式为原始设计模式。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">但是遗憾的是，越来越方便的框架支持，领域模型简化造成代码过程化、脚本化，使得在企业应用中很难看到原始设计模式的影子（当然还是可以看到遍地的命令模式）。比如：</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">IoC</span>
						<span style="font-family: 宋体;">容器将单例、工厂、原型模式包装了起来，你现在需要做的仅仅是填写配置文件；框架集成了观察者、模版等等模式，你仅仅按照框架说明实现具体对象就可以了；过程化、脚本化的代码里面更不要提什么设计模式了！更甚者在</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">EJB</span>
						<span style="font-family: 宋体;">中单例模式差点变成了反模式。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">原
始的设计模式没有用，过时了吗？如果你不甘心仅仅做一名代码组装工；想对你们部门的高手设计的框架品头论足的话，答案就是否定的。原始设计模式有很多的确
是难得一见了，但是了解它们绝对不是在浪费你的时间，它可以让你在解决问题的时候思路更开阔一些——它的思想比它的架势更重要。</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
								<span style="">          </span>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">写在最后（其实应该在最前面）</span>
						<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						</span>
				</font>
		</p>
		<font size="3">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<span style="">    </span>
				</span>
				<span style="font-family: 宋体;">细想自己在学习设计模式时，常常埋怨《</span>
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">Java</span>
				<span style="font-family: 宋体;">与模式》肤浅无物，为了模式而模式；又感叹</span>
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">GOF</span>
				<span style="font-family: 宋体;">写
得高度概括，苦于理解。于是便有了将自己对设计模式的认识写下来的想法。正巧参与了部门组织的一次设计模式讲座，触发了第一篇文章的诞生。从现在来看，文
章倒是全写成了，可内容上却不能让自己满意，却又懒得动手修改（谈何容易）。“深入”二字说来容易，做到何其难，自以为这些文章的分量远远够不上；倒是
“浅出”，自以为还可以沾上点边。你可以把本系列文章看作是《</span>
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">Java</span>
				<span style="font-family: 宋体;">与模式》的替代品，帮你叩开设计模式之门。如果你要深入研究设计模式，我劝你还是去研读《设计模式》一书吧。</span>
		</font>
<img src ="http://www.blogjava.net/alex/aggbug/66486.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 17:56 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66486.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]深入浅出工厂模式</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66479.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 09:26:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66479.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66479.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66479.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66479.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">
						<font size="3">一、引子</font>
				</span>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">      <span style=""></span></font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">话说十年前，有一个暴发户，他家有三辆汽车</span>
						<span style="font-family: Tahoma;" lang="EN-US">——Benz</span>
						<span style="font-family: 宋体;">奔驰、</span>
						<span style="font-family: Tahoma;" lang="EN-US">Bmw</span>
						<span style="font-family: 宋体;">宝马、</span>
						<span style="font-family: Tahoma;" lang="EN-US">Audi</span>
						<span style="font-family: 宋体;">奥迪，还雇了司机为他开车。不过，暴发户坐车时总是怪怪的：上</span>
						<span style="font-family: Tahoma;" lang="EN-US">Benz</span>
						<span style="font-family: 宋体;">车后跟司机说</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">开奔驰车！</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">，坐上</span>
						<span style="font-family: Tahoma;" lang="EN-US">Bmw</span>
						<span style="font-family: 宋体;">后他说</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">开宝马车！</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">，坐上</span>
						<span style="font-family: Tahoma;" lang="EN-US">Audi</span>
						<span style="font-family: 宋体;">说</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">开奥迪车！</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">。你一定说：这人有病！直接说开车不就行了？！</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">       </font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">而当把这个暴发户的行为放到我们程序设计中来时，会发现这是一个普遍存在的现象。幸运的是，这种有病的现象在</span>
						<span style="font-family: Tahoma;" lang="EN-US">OO</span>
						<span style="font-family: 宋体;">（面向对象）语言中可以避免了。下面就以</span>
						<span style="font-family: Tahoma;" lang="EN-US">Java</span>
						<span style="font-family: 宋体;">语言为基础来引入我们本文的主题：工厂模式。</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<br />
				</span>
				<span style="font-family: 宋体;">
						<font size="3">二、分类</font>
				</span>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">
								<span style=""> </span>
								<span style="">     </span>
						</font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">工厂模式主要是为创建对象提供过渡接口，以便将创建对象的具体过程屏蔽隔离起来，达到提高灵活性的目的。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">工厂模式在《</span>
						<span style="font-family: Tahoma;" lang="EN-US">Java</span>
						<span style="font-family: 宋体;">与模式》中分为三类：</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">      <span style=""></span>1</font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">）简单工厂模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Simple Factory</span>
						<span style="font-family: 宋体;">）</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">2</span>
						<span style="font-family: 宋体;">）工厂方法模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Factory Method</span>
						<span style="font-family: 宋体;">）</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">3</span>
						<span style="font-family: 宋体;">）抽象工厂模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Abstract Factory</span>
						<span style="font-family: 宋体;">）</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">      <span style=""></span></font>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">这三种模式从上到下逐步抽象，并且更具一般性。</font>
				</span>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">    <span style="">   </span>GOF</font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">在《设计模式》一书中将工厂模式分为两类：工厂方法模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Factory Method</span>
						<span style="font-family: 宋体;">）与抽象工厂模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Abstract Factory</span>
						<span style="font-family: 宋体;">）。将简单工厂模式（</span>
						<span style="font-family: Tahoma;" lang="EN-US">Simple Factory</span>
						<span style="font-family: 宋体;">）看为工厂方法模式的一种特例，两者归为一类。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">两者皆可，在本文使用《</span>
						<span style="font-family: Tahoma;" lang="EN-US">Java</span>
						<span style="font-family: 宋体;">与模式》的分类方法。下面来看看这些工厂模式是怎么来</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">治病</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">的。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">三、简单工厂模式</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="left">
				<span style="font-family: 宋体;">
						<font size="3">简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单：定义一个用于创建对象的接口。</font>
				</span>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">      <span style=""></span></font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">先来看看它的组成：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; text-align: left;" align="left">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">工厂类角色：这是本模式的核心，含有一定的商业逻辑和判断逻辑。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中它往往由一个具体类实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; text-align: left;" align="left">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象产品角色：它一般是具体产品继承的父类或者实现的接口。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中由接口或者抽象类来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; text-align: left;" align="left">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">3)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体产品角色：工厂类所创建的对象就是此角色的实例。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中由一个具体类实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="left">
				<font size="3">
						<span style="font-family: 宋体;">来用类图来清晰的表示下的它们之间的关系（如果对类图不太了解，请参考我关于类图的文章）：</span>
						<span style="font-family: Tahoma;" lang="EN-US"> </span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left;" align="center">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<img src="http://blog.csdn.net/images/blog_csdn_net/ai92/76417/r_%E7%AE%80%E5%8D%95%E5%B7%A5%E5%8E%82.jpg" alt="" height="150" width="358" />
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">那么简单工厂模式怎么来使用呢？我们就以简单工厂模式来改造暴发户坐车的方式</span>
						<span style="font-family: Tahoma;" lang="EN-US">——</span>
						<span style="font-family: 宋体;">现在暴发户只需要坐在车里对司机说句：</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">开车</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">就可以了。</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br style="" />
						<br style="" />
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">抽象产品角色</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public interface Car{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public void drive(); <br />}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">具体产品角色</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">public class Benz implements Car{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public void drive()<span style="">  </span>{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">System.out.println("Driving Benz "); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">} </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">} </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class Bmw implements Car{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public void drive()<span style="">  </span>{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">System.out.println("Driving Bmw "); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">} </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">}<br /></span>
						<span style="font-family: 宋体;">。。。（奥迪我就不写了</span>
						<span style="font-family: Tahoma;" lang="EN-US">:P</span>
						<span style="font-family: 宋体;">）</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<br />
						<font size="3">//</font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">工厂类角色</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class Driver{</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 42pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">工厂方法</span>
						<span style="font-family: Tahoma;" lang="EN-US">.</span>
						<span style="font-family: 宋体;">注意</span>
						<span style="font-family: Tahoma;">
						</span>
						<span style="font-family: 宋体;">返回类型为抽象产品角色</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">
								<span style="">       </span>public <span style="background: yellow none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">static</span><span style="background: yellow none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Car</span> driverCar(String s)throws Exception<span style="">    </span>{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">          <span style="">    </span>//</span>
						<span style="font-family: 宋体;">判断逻辑，返回具体的产品角色给</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">Client<br /><span style="">              </span>if(s.equalsIgnoreCase("Benz"))<span style="">   </span></font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                     </span>return new Benz(); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>else if(s.equalsIgnoreCase("Bmw")) </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                     </span>return new Bmw(); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">                    ......   <br />             else throw new Exception(); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">。。。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">//</font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">欢迎暴发户出场</span>
						<span style="font-family: Tahoma;" lang="EN-US">......</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">public class Magnate{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>public static void main(String[] args){ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">              </span>try{ <br />                   <span style="">  </span>//</span>
						<span style="font-family: 宋体;">告诉司机我今天坐奔驰</span>
				</font>
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">              <br /><span style="">                     </span>Car car = Driver.driverCar("benz"); <br />                   <span style="">  </span>//</span>
						<span style="font-family: 宋体;">下命令：开车</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">                   <br /><span style="">                     </span>car.drive(); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">              </span>
						</span>
						<span style="font-family: 宋体;">。。。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">    </span>
						<span style="font-family: 宋体;">将本程序空缺的其他信息填充完整后即可运行。如果你将所有的类放在一个文件中，请不要忘记只能有一个类被声明为</span>
						<span style="font-family: Tahoma;" lang="EN-US">public</span>
						<span style="font-family: 宋体;">。本程序在</span>
						<span style="font-family: Tahoma;" lang="EN-US">jdk1.4 </span>
						<span style="font-family: 宋体;">下运行通过。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">      </span>
						<span style="font-family: 宋体;">程序中各个类的关系表达如下：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> <img style="width: 498px; height: 230px;" src="http://blog.csdn.net/images/blog_csdn_net/ai92/76417/r_%E7%AE%80%E5%8D%95%E5%B7%A5%E5%8E%821.jpg" alt="" height="246" width="533" /></font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">这便是简单工厂模式了。怎么样，使用起来很简单吧？那么它带来了什么好处呢？</font>
				</span>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">     <span style="">  </span></font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">首先，使用了简单工厂模式后，我们的程序不在</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">有病</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">，更加符合现实中的情况；而且客户端免除了直接创建产品对象的责任，而仅仅负责</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">消费</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">产品（正如暴发户所为）。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">      <span style=""></span></span>
						<span style="font-family: 宋体;">下
面我们从开闭原则（对扩展开放；对修改封闭）上来分析下简单工厂模式。当暴发户增加了一辆车的时候，只要符合抽象产品制定的合同，那么只要通知工厂类知道
就可以被客户使用了。所以对产品部分来说，它是符合开闭原则的；但是工厂部分好像不太理想，因为每增加一辆车，都要在工厂类中增加相应的业务逻辑或者判断
逻辑，这显然是违背开闭原则的。可想而知对于新产品的加入，工厂类是很被动的。对于这样的工厂类（在我们的例子中是为司机师傅），我们称它为全能类或者上
帝类。</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">      <span style=""></span></font>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">我们举的例子是最简单的情况，而在实际应用中，很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品，所以这可能会把我们的上帝累坏了，也累坏了我们这些程序员</font>
				</span>
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">:(<br />      <span style=""></span></span>
						<span style="font-family: 宋体;">于是工厂方法模式作为救世主出现了。</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<br style="" />
								<br style="" />
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">四、工厂方法模式</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">工厂方法模式去掉了简单工厂模式中工厂方法的静态属性，使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">你应该大致猜出了工厂方法模式的结构，来看下它的组成：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象工厂角色：</span>
						<span style="font-family: Tahoma;" lang="EN-US"> </span>
						<span style="font-family: 宋体;">这是工厂方法模式的核心，它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中它由抽象类或者接口来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体工厂角色：它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">3)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象产品角色：它是具体产品继承的父类或者是实现的接口。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中一般有抽象类或者接口来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">4)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体产品角色：具体工厂角色所创建的对象就是此角色的实例。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中由具体的类来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">用类图来清晰的表示下的它们之间的关系：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<p>
										<img src="http://blog.csdn.net/images/blog_csdn_net/ai92/76417/r_%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95.jpg" alt="" height="251" width="554" />
								</p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的</span>
						<span style="font-family: Tahoma;" lang="EN-US">“</span>
						<span style="font-family: 宋体;">上帝类</span>
						<span style="font-family: Tahoma;" lang="EN-US">”</span>
						<span style="font-family: 宋体;">。正如上面所说，这样便分担了对象承受的压力；而且这样使得结构变得灵活起来</span>
						<span style="font-family: Tahoma;" lang="EN-US">——</span>
						<span style="font-family: 宋体;">当有新的产品（即暴发户的汽车）产生时，只要按照抽象产品角色、抽象工厂角色提供的合同来生成，那么就可以被客户使用，而不必去修改任何已有的代码。可以看出工厂角色的结构也是符合开闭原则的！</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">我
们还是老规矩，使用一个完整的例子来看看工厂模式各个角色之间是如何来协调的。话说暴发户生意越做越大，自己的爱车也越来越多。这可苦了那位司机师傅了，
什么车它都要记得，维护，都要经过他来使用！于是暴发户同情他说：看你跟我这么多年的份上，以后你不用这么辛苦了，我给你分配几个人手，你只管管好他们就
行了！于是，工厂方法模式的管理出现了。代码如下：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">抽象产品角色，具体产品角色与简单工厂模式类似，只是变得复杂了些，这里略。</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">//</font>
				</span>
				<span style="font-family: 宋体;">
						<font size="3">抽象工厂角色</font>
				</span>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">public interface Driver{<br /><span style="">       </span>public Car driverCar();<br />}<br />public class BenzDriver implements Driver{<br /><span style="">       </span>public Car driverCar(){<br /><span style="">       </span><span style="">       </span>return new Benz();<br /><span style="">       </span>}<br />}<br />public class BmwDriver implements Driver{<br /><span style="">       </span>public Car driverCar()<span style="">   </span>{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: 42pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">return new Bmw(); <br /><span style="">       </span>}<br />}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">//</span>
						<span style="font-family: 宋体;">应该和具体产品形成对应关系</span>
				</font>
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">...<br />//</span>
						<span style="font-family: 宋体;">有请暴发户先生</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3"> public class Magnate </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style="">       </span>public static void main(String[] args) </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>
								<span style="">       </span>{ </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>
								<span style="">       </span>try{ <br />                 <span style="">           </span>Driver driver = new BenzDriver(); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                     </span>
								<span style="">       </span>Car car = driver.driverCar(); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">                     </span>
								<span style="">       </span>car.drive(); </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">              </span>
								<span style="">       </span>}</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">
								<span style="">       </span>……</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<font size="3">} </font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">可
以看出工厂方法的加入，使得对象的数量成倍增长。当产品种类非常多时，会出现大量的与之对应的工厂对象，这不是我们所希望的。因为如果不能避免这种情况，
可以考虑使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类：即对于产品树上类似的种类（一般是树的叶子中互为兄弟的）使用简单工厂模式来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">五、小结</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">工厂方法模式仿佛已经很完美的对对象的创建进行了包装，使得客户程序中仅仅处理抽象产品角色提供的接口。那我们是否一定要在代码中遍布工厂呢？大可不必。也许在下面情况下你可以考虑使用工厂方法模式：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">当客户程序不需要知道要使用对象的创建过程。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">客户程序使用的对象存在变动的可能，或者根本就不知道使用哪一个具体的对象。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">简
单工厂模式与工厂方法模式真正的避免了代码的改动了？没有。在简单工厂模式中，新产品的加入要修改工厂角色中的判断语句；而在工厂方法模式中，要么将判断
逻辑留在抽象工厂角色中，要么在客户程序中将具体工厂角色写死（就象上面的例子一样）。而且产品对象创建条件的改变必然会引起工厂角色的修改。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">
								<span style="">       </span>
						</span>
						<span style="font-family: 宋体;">面对这种情况，</span>
						<span style="font-family: Tahoma;" lang="EN-US">Java</span>
						<span style="font-family: 宋体;">的反射机制与配置文件的巧妙结合突破了限制</span>
						<span style="font-family: Tahoma;" lang="EN-US">——</span>
						<span style="font-family: 宋体;">这在</span>
						<span style="font-family: Tahoma;" lang="EN-US">Spring</span>
						<span style="font-family: 宋体;">中完美的体现了出来。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> </font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: 宋体;">六、抽象工厂模式</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font size="3">
						<span style="font-family: Tahoma;" lang="EN-US">      </span>
						<span style="font-family: 宋体;">先来认识下什么是产品族：</span>
						<span style="font-family: Tahoma;">
						</span>
						<span style="font-family: 宋体;">位于不同产品等级结构中，功能相关联的产品组成的家族。还是让我们用一个例子来形象地说明一下吧。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<p>
								<font size="3"> <img src="http://blog.csdn.net/images/blog_csdn_net/ai92/76417/r_factory.jpg" alt="" height="231" width="583" /></font>
						</p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">图中的</span>
						<span style="font-family: Tahoma;" lang="EN-US">BmwCar</span>
						<span style="font-family: 宋体;">和</span>
						<span style="font-family: Tahoma;" lang="EN-US">BenzCar</span>
						<span style="font-family: 宋体;">就是两个产品树（产品层次结构）；而如图所示的</span>
						<span style="font-family: Tahoma;" lang="EN-US">BenzSportsCar</span>
						<span style="font-family: 宋体;">和</span>
						<span style="font-family: Tahoma;" lang="EN-US">BmwSportsCar</span>
						<span style="font-family: 宋体;">就是一个产品族。他们都可以放到跑车家族中，因此功能有所关联。同理</span>
						<span style="font-family: Tahoma;" lang="EN-US">BmwBussinessCar</span>
						<span style="font-family: 宋体;">和</span>
						<span style="font-family: Tahoma;" lang="EN-US">BenzSportsCar</span>
						<span style="font-family: 宋体;">也是一个产品族。</span>
				</font>
				<span style="font-family: Tahoma;" lang="EN-US">
						<br />
						<font size="3">      </font>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">回到抽象工厂模式的话题上。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">可以说，抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">抽象工厂模式的用意为：给客户端提供一个接口，可以创建多个产品族中的产品对象</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">而且使用抽象工厂模式还要满足一下条件：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">系统中有多个产品族，而系统一次只可能消费其中一族产品。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">同属于同一个产品族的产品以其使用。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">来看看抽象工厂模式的各个角色（和工厂方法的如出一辙）：</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">1)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象工厂角色：</span>
						<span style="font-family: Tahoma;" lang="EN-US"> </span>
						<span style="font-family: 宋体;">这是工厂方法模式的核心，它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中它由抽象类或者接口来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">2)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体工厂角色：它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中它由具体的类来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">3)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">抽象产品角色：它是具体产品继承的父类或者是实现的接口。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中一般有抽象类或者接口来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
						<span style="">
								<font size="3">4)</font>
								<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">        </span>
						</span>
				</span>
				<font size="3">
						<span style="font-family: 宋体;">具体产品角色：具体工厂角色所创建的对象就是此角色的实例。在</span>
						<span style="font-family: Tahoma;" lang="EN-US">java</span>
						<span style="font-family: 宋体;">中由具体的类来实现。</span>
						<span style="font-family: Tahoma;" lang="EN-US">
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">类图如下：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">
						</span>
						<span style="font-family: Tahoma;" lang="EN-US">
								<p>
										<img style="width: 544px; height: 347px;" src="http://blog.csdn.net/images/blog_csdn_net/ai92/76417/r_%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82.jpg" alt="" height="358" width="580" />
								</p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: Tahoma;" lang="EN-US">
				</span>
		</p>
		<span style="font-family: 宋体;">
				<font size="3">看过了前两个模式，对这个模式各个角色之间的协调情况应该心里有个数了，我就不举具体的例子了。只是一定要注意满足使用抽象工厂模式的条件哦。</font>
		</span>
<img src ="http://www.blogjava.net/alex/aggbug/66479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 17:26 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]设计模式之Factory</title><link>http://www.blogjava.net/alex/archive/2006/08/29/66476.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 29 Aug 2006 09:13:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/29/66476.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66476.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/29/66476.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66476.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66476.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>在本例中，首先，我们需要将创建实例的工作与使用实例的工作分开<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%;" border="0" cellpadding="0" cellspacing="3" width="80%">
				<tbody>
						<tr>
								<td style="padding: 2.25pt; background: rgb(204, 204, 204) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
										<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 src="http://www.jdon.com/designpatterns/images/factory.jpg" height="178" 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%;" border="0" cellpadding="0" cellspacing="3" width="100%">
				<tbody>
						<tr>
								<td style="padding: 2.25pt; background: rgb(204, 204, 204) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
										<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>
						<o:p>
						</o:p>
				</span>
		</p>
		<p>我们以<span lang="EN-US">Jive的ForumFactory为例，这个例子在前面的Singleton模式中我们讨论过，现在再讨论其工厂模式:</span></p>
		<table style="width: 97%;" border="0" cellpadding="0" cellspacing="3" width="97%">
				<tbody>
						<tr>
								<td style="padding: 2.25pt; background: rgb(204, 204, 204) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
										<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 bgcolor="#cccccc" border="0" cellpadding="0" cellspacing="0" width="100%">
				<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="" 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/alex/aggbug/66476.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-29 17:13 <a href="http://www.blogjava.net/alex/archive/2006/08/29/66476.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java IO 包中的Decorator模式</title><link>http://www.blogjava.net/alex/archive/2006/08/10/62859.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 10 Aug 2006 13:04:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/10/62859.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/62859.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/10/62859.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/62859.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/62859.html</trackback:ping><description><![CDATA[key words: decorator 装饰模式 jdk中的装饰模式<br /><br /><span class="article-table-text"><p>JDK为程序员提供了大量的类库，而为了保持类库的可重用性，可扩展性和灵活性，其中使用到了大量的设计模式，本文将介绍JDK的I/O包中使用到的Decorator模式，并运用此模式，实现一个新的输出流类。 <br /><br /><strong>　　Decorator模式简介 </strong><br /><br />　　Decorator模式又名包装器(Wrapper)，它的主要用途在于给一个对象动态的添加一些额外的职责。与生成子类相比，它更具有灵活性。<br />有
时候，我们需要为一个对象而不是整个类添加一些新的功能，比如，给一个文本区添加一个滚动条的功能。我们可以使用继承机制来实现这一功能，但是这种方法不
够灵活，我们无法控制文本区加滚动条的方式和时机。而且当文本区需要添加更多的功能时，比如边框等，需要创建新的类，而当需要组合使用这些功能时无疑将会
引起类的爆炸。<br /><br />　　我们可以使用一种更为灵活的方法，就是把文本区嵌入到滚动条中。而这个滚动条的类就相当于对文本区的一个<strong>装饰</strong>。
这个装饰(滚动条)必须与被装饰的组件(文本区)继承自同一个接口，这样，用户就不必关心装饰的实现，因为这对他们来说是透明的。装饰会将用户的请求转发
给相应的组件(即调用相关的方法)，并可能在转发的前后做一些额外的动作(如添加滚动条)。通过这种方法，我们可以根据组合对文本区嵌套不同的装饰，从而
添加任意多的功能。这种动态的对对象添加功能的方法不会引起类的爆炸，也具有了更多的灵活性。<br /><br />　　以上的方法就是<strong>Decorator模式</strong>，它通过给对象添加装饰来动态的添加新的功能。如下是Decorator模式的UML图：</p><p align="center"><br /><img o&shy;nmousewheel="return bbimg(this)" src="http://cimg.163.com/catchpic/E/EF/EFD7757ECF4A444F276835913426D10D.jpg" o&shy;nload="javascript­:resizepic(this)" border="0" height="288" width="391" /></p><p><br />　　Component为组件和装饰的公共父类，它定义了子类必须实现的方法。<br /><br />　　ConcreteComponent是一个具体的组件类，可以通过给它添加装饰来增加新的功能。<br /><br />　　Decorator是所有装饰的公共父类，它定义了所有装饰必须实现的方法，同时，它还保存了一个对于Component的引用，以便将用户的请求转发给Component，并可能在转发请求前后执行一些附加的动作。<br /><br />　　ConcreteDecoratorA和ConcreteDecoratorB是具体的装饰，可以使用它们来装饰具体的Component。<br /><br /><strong>　　Java IO包中的Decorator模式</strong><br /><br />　　JDK提供的java.io包中使用了Decorator模式来实现对各种输入输出流的封装。以下将以java.io.OutputStream及其子类为例，讨论一下Decorator模式在IO中的使用。<br /><br />　　首先来看一段用来创建IO流的代码：<br /><br /><font face="新宋体"><code><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />try { <br />　OutputStream out = new DataOutputStream(new FileOutputStream("test.txt")); <br />} catch (FileNotFoundException e) { <br />　e.printStackTrace(); <br />}</code><br /></font>　
　这段代码对于使用过JAVA输入输出流的人来说再熟悉不过了，我们使用DataOutputStream封装了一个FileOutputStream。
这是一个典型的Decorator模式的使用，FileOutputStream相当于Component，DataOutputStream就是一个
Decorator。将代码改成如下，将会更容易理解：<br /><br /><font face="新宋体"><code><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />try { <br />　OutputStream out = new FileOutputStream("test.txt"); <br />　out = new DataOutputStream(out); <br />} catch(FileNotFoundException e) { <br />　e.printStatckTrace(); <br />}</code><br /></font>　　由于FileOutputStream和DataOutputStream有公共的父类OutputStream，因此对对象的装饰对于用户来说几乎是透明的。下面就来看看OutputStream及其子类是如何构成Decorator模式的：</p><p align="center"><br /><img o&shy;nmousewheel="return bbimg(this)" src="http://cimg.163.com/catchpic/5/5F/5FD3B7C491357BE01991CC6406584520.jpg" o&shy;nload="javascript­:resizepic(this)" border="0" height="225" width="567" /></p><p><br />OutputStream是一个抽象类，它是所有输出流的公共父类，其源代码如下： <br /><br /><code><font face="新宋体"><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />public abstract class OutputStream implements Closeable, Flushable { <br />public abstract void write(int b) throws IOException; <br />... <br />}</font></code><br />它定义了write(int b)的抽象方法。这相当于Decorator模式中的Component类。 <br /><br />ByteArrayOutputStream，FileOutputStream 和 PipedOutputStream 三个类都直接从OutputStream继承，以ByteArrayOutputStream为例： <br /><br /><code><font face="新宋体"><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />public class ByteArrayOutputStream extends OutputStream { <br />protected byte buf[]; <br />protected int count; <br />public ByteArrayOutputStream() { <br />this(32); <br />} <br />public ByteArrayOutputStream(int size) { <br />if (size 〈 0) { <br />throw new IllegalArgumentException("Negative initial size: " + size); <br />} <br />buf = new byte[size]; <br />} <br />public synchronized void write(int b) { <br />int newcount = count + 1; <br />if (newcount 〉 buf.length) { <br />byte newbuf[] = new byte[Math.max(buf.length 〈〈 1, newcount)]; <br />System.arraycopy(buf, 0, newbuf, 0, count); <br />buf = newbuf; <br />} <br />buf[count] = (byte)b; <br />count = newcount; <br />} <br />... <br />}</font></code><br />它实现了OutputStream中的write(int b)方法，因此我们可以用来创建输出流的对象，并完成特定格式的输出。它相当于Decorator模式中的ConcreteComponent类。 <br /><br />接着来看一下FilterOutputStream，代码如下： <br /><br /><code><font face="新宋体"><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />public class FilterOutputStream extends <u>OutputStream</u> { <br /><font color="#ff0000">protected OutputStream out; </font><br />public FilterOutputStream(OutputStream out) { <br />this.out = out; <br />} <br /></font><font face="新宋体"><strong>public void write(int b) throws IOException { <br />out.write(b); <br />} <br /></strong>... <br />}</font></code><br />同
样，它也是从OutputStream继承。</p><p><font color="#ff0000">但是，它的构造函数很特别，需要传递一个OutputStream的引用给它，并且它将保存对此对象的引用。</font>
而如果没有具体的OutputStream对象存在，我们将无法创建FilterOutputStream。<font color="#ff0000">由于out既可以是指向
FilterOutputStream类型的引用，也可以是指向ByteArrayOutputStream等具体输出流类的引用，因此使用多层嵌套的方
式，我们可以为ByteArrayOutputStream添加多种装饰。</font>这个FilterOutputStream类相当于Decorator模式中的
Decorator类，它的write(int b)方法只是简单的调用了传入的流的write(int
b)方法，而没有做更多的处理，因此它本质上没有对流进行装饰，所以继承它的子类必须覆盖此方法，以达到装饰的目的。 <br /><br />BufferedOutputStream
和
DataOutputStream是FilterOutputStream的两个子类，它们相当于Decorator模式中的
ConcreteDecorator，并对传入的输出流做了不同的装饰。以BufferedOutputStream类为例： <br /><br /><code><font face="新宋体"><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />public class BufferedOutputStream extends FilterOutputStream { <br />... <br />private void flushBuffer() throws IOException { <br />if (count 〉 0) { <br />out.write(buf, 0, count); <br />count = 0; <br />} <br />} <br />public synchronized void write(int b) throws IOException { <br />if (count 〉= buf.length) { <br />flushBuffer(); <br />} <br />buf[count++] = (byte)b; <br />} <br />... <br />}</font></code></p><p><br />　
　这个类提供了一个缓存机制，等到缓存的容量达到一定的字节数时才写入输出流。首先它继承了FilterOutputStream，并且覆盖了父类的
write(int b)方法，在调用输出流写出数据前都会检查缓存是否已满，如果未满，则不写。这样就实现了对输出流对象动态的添加新功能的目的。<br /><br />　　下面，将使用Decorator模式，为IO写一个新的输出流。</p><p>　　<strong>自己写一个新的输出流</strong><br /><br />　
　了解了OutputStream及其子类的结构原理后，我们可以写一个新的输出流，来添加新的功能。这部分中将给出一个新的输出流的例子，它将过滤待输
出语句中的空格符号。比如需要输出"java io
OutputStream"，则过滤后的输出为"javaioOutputStream"。以下为SkipSpaceOutputStream类的代码：<br /><br /><font face="新宋体"><code><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />import java.io.FilterOutputStream; <br />import java.io.IOException; <br />import java.io.OutputStream; <br />/** <br />* A new output stream, which will check the space character <br />* and won’t write it to the output stream. <br />* @author Magic <br />* <br />*/ <br />public class SkipSpaceOutputStream extends FilterOutputStream { <br />　public SkipSpaceOutputStream(OutputStream out) { <br />　　super(out); <br />　} <br />　/** <br />　* Rewrite the method in the parent class, and <br />　* skip the space character. <br />　*/ <br />　public void write(int b) throws IOException{ <br />　　if(b!=’ ’){ <br />　　　super.write(b); <br />　　} <br />　} <br />}</code><br /></font>　　它从FilterOutputStream继承，并且重写了它的write(int b)方法。在write(int b)方法中首先对输入字符进行了检查，如果不是空格，则输出。<br /><br />　　以下是一个测试程序：<br /><br /><font face="新宋体"><code><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是代码片段：</font><br />import java.io.BufferedInputStream; <br />import java.io.DataInputStream; <br />import java.io.DataOutputStream; <br />import java.io.IOException; <br />import java.io.InputStream; <br />import java.io.OutputStream; <br />/** <br />* Test the SkipSpaceOutputStream. <br />* @author Magic <br />* <br />*/ <br />public class Test { <br />　public static void main(String[] args){ <br />　　byte[] buffer = new byte[1024]; <br /><br />　　/** <br />　　* Create input stream from the standard input. <br />　　*/ <br />　　InputStream in = new BufferedInputStream(new DataInputStream(System.in)); <br /><br />　　/** <br />　　* write to the standard output. <br />　　*/ <br />　　OutputStream out = new SkipSpaceOutputStream(new DataOutputStream(System.out)); <br /><br />　　try { <br />　　　System.out.println("Please input your words: "); <br />　　　int n = in.read(buffer,0,buffer.length); <br />　　　for(int i=0;i〈n;i++){ <br />　　　　out.write(buffer[i]); <br />　　　} <br />　　} catch (IOException e) { <br />　　　e.printStackTrace(); <br />　　} <br />　} <br />}</code><br /></font>　　执行以上测试程序，将要求用户在console窗口中输入信息，程序将过滤掉信息中的空格，并将最后的结果输出到console窗口。比如：<br /><br /><font face="新宋体"><code bgcolor="#f3f3f3"><font style="font-weight: bold; color: rgb(153, 0, 0);">以下是引用片段：</font><br />Please input your words: <br />a b c d e f <br />abcdef</code><br /></font><strong>　　总 结</strong><br /><br />　
　在java.io包中，不仅OutputStream用到了Decorator设计模式，InputStream，Reader，Writer等都用到
了此模式。而作为一个灵活的，可扩展的类库，JDK中使用了大量的设计模式，比如在Swing包中的MVC模式，RMI中的Proxy模式等等。对于
JDK中模式的研究不仅能加深对于模式的理解，而且还有利于更透彻的了解类库的结构和组成</p>(转载文章请保留出处：<a href="http://www.javajia.com/">Java家(www.javajia.com)</a>)</span><br /><img src ="http://www.blogjava.net/alex/aggbug/62859.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-10 21:04 <a href="http://www.blogjava.net/alex/archive/2006/08/10/62859.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Observer(观察者 )</title><link>http://www.blogjava.net/alex/archive/2006/08/07/62229.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 07 Aug 2006 12:07:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/07/62229.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/62229.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/07/62229.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/62229.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/62229.html</trackback:ping><description><![CDATA[key words: 观察者模式 Observer模式<br /><br />definition:<br />defines a one-to-many dependency between objects so that when one object changes state,all of its dependents are notified and updated automatically.<br /><br />物理模型:<br /><b> 观察者注册</b><br /><img src="http://www.blogjava.net/images/blogjava_net/alex/images/observerpattern_02.gif" alt="observerpattern_02.gif" border="0" height="194" width="383" /><br /><br />观察者通知:<br /><img src="http://www.blogjava.net/images/blogjava_net/alex/images/observerpattern_03.gif" alt="observerpattern_03.gif" border="0" height="260" width="338" /><br />观察者撤销注册<br /><img src="http://www.blogjava.net/images/blogjava_net/alex/images/observerpattern_04.gif" alt="observerpattern_04.gif" border="0" height="196" width="377" /><br /><br />business: weather station<br />天气预报，在预报的数据更新后自动通知到各类不同显示类型的终端，前提是这些终端向预报中心注册了预定服务(register the service),这一点类似于订阅报纸，你'订阅'了以后就可以呆在家等邮递员给你送过来.<br />看一下类图:<img src="http://www.blogjava.net/images/blogjava_net/alex/images/weather.png" alt="weather.png" border="0" height="800" width="804" /><br /><img src="/WebResource.axd?d=pLXXeGbWF7eXU8SMs2-GFZvUWY2JNH05dFx5YzJhGUYAYJAFEaTEq36NAhTPy7_KekvzDFwt8wvQWdByvJIGWdEq6x2KpKD80&amp;t=632785713320000000" height="1" width="1" /><br /><br />implement:<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">interface</span><span style="color: rgb(0, 0, 0);"> Subject {<br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> registerObserver(Observer o);<br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> removeObserver(Observer o);<br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> notifyObservers();<br />}</span></div><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> WeatherData </span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);"> Subject {<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> ArrayList observers;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> temperature;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> humidity;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> pressure;<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> WeatherData() {<br />        observers </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> ArrayList();<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> registerObserver(Observer o) {<br />        observers.add(o);<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> removeObserver(Observer o) {<br />        </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> i </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> observers.indexOf(o);<br />        </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (i </span><span style="color: rgb(0, 0, 0);">&gt;=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">) {<br />            observers.remove(i);<br />        }<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> notifyObservers() {<br />        </span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> i </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">; i </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> observers.size(); i</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">) {<br />            Observer observer </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (Observer)observers.get(i);<br />            observer.update(temperature, humidity, pressure);<br />        }<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> measurementsChanged() {<br />        notifyObservers();<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setMeasurements(</span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> temperature, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> humidity, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> pressure) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.temperature </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> temperature;<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.humidity </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> humidity;<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.pressure </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> pressure;<br />        measurementsChanged();<br />    }<br />    <br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> other WeatherData methods here</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> getTemperature() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> temperature;<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> getHumidity() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> humidity;<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> getPressure() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> pressure;<br />    }<br />}<br /></span></div><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">interface</span><span style="color: rgb(0, 0, 0);"> Observer {<br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> update(</span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> temp, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> humidity, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> pressure);<br />}<br /></span></div><br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">interface</span><span style="color: rgb(0, 0, 0);"> DisplayElement {<br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> display();<br />}<br /></span></div><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> CurrentConditionsDisplay </span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);"> Observer, DisplayElement {<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> temperature;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> humidity;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> Subject weatherData;<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> CurrentConditionsDisplay(Subject weatherData) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.weatherData </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> weatherData;<br />        weatherData.registerObserver(</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">);<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> update(</span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> temperature, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> humidity, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> pressure) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.temperature </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> temperature;<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.humidity </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> humidity;<br />        display();<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> display() {<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Current conditions: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> temperature <br />            </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">F degrees and </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> humidity </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">% humidity</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />    }<br />}</span></div><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> WeatherStation {<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> main(String[] args) {<br />        WeatherData weatherData </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> WeatherData();<br />    <br />         //register to weatherData(subscribe to weatherData)<br />        CurrentConditionsDisplay currentDisplay </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> CurrentConditionsDisplay(weatherData);<br />        StatisticsDisplay statisticsDisplay </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> StatisticsDisplay(weatherData);<br />        ForecastDisplay forecastDisplay </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> ForecastDisplay(weatherData);<br /><br />        weatherData.setMeasurements(</span><span style="color: rgb(0, 0, 0);">80</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">65</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">30.4f</span><span style="color: rgb(0, 0, 0);">);<br />        weatherData.setMeasurements(</span><span style="color: rgb(0, 0, 0);">82</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">70</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">29.2f</span><span style="color: rgb(0, 0, 0);">);<br />        weatherData.setMeasurements(</span><span style="color: rgb(0, 0, 0);">78</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">90</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">29.2f</span><span style="color: rgb(0, 0, 0);">);<br />    }<br />}<br /></span></div><br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> WeatherStationHeatIndex {<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> main(String[] args) {<br />        WeatherData weatherData </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> WeatherData();<br />        CurrentConditionsDisplay currentDisplay </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> CurrentConditionsDisplay(weatherData);<br />        StatisticsDisplay statisticsDisplay </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> StatisticsDisplay(weatherData);<br />        ForecastDisplay forecastDisplay </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> ForecastDisplay(weatherData);<br />        HeatIndexDisplay heatIndexDisplay </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> HeatIndexDisplay(weatherData);<br /><br />        weatherData.setMeasurements(</span><span style="color: rgb(0, 0, 0);">80</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">65</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">30.4f</span><span style="color: rgb(0, 0, 0);">);<br />        weatherData.setMeasurements(</span><span style="color: rgb(0, 0, 0);">82</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">70</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">29.2f</span><span style="color: rgb(0, 0, 0);">);<br />        weatherData.setMeasurements(</span><span style="color: rgb(0, 0, 0);">78</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">90</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">29.2f</span><span style="color: rgb(0, 0, 0);">);<br />    }<br />}</span></div><br /><br />other places to use Observe-Pattern in JDK:<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> SwingObserverExample {<br />    JFrame frame;<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> main(String[] args) {<br />        SwingObserverExample example </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> SwingObserverExample();<br />        example.go();<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> go() {<br />        frame </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> JFrame();<br /><br />        JButton button </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> JButton(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Should I do it?</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />         //register to AngelListener and DevilListener<br /><br />        button.addActionListener(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> AngelListener());<br />        button.addActionListener(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> DevilListener());<br />        frame.getContentPane().add(BorderLayout.CENTER, button);<br /><br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> Set frame properties </span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />        frame.getContentPane().add(BorderLayout.CENTER, button);<br />        frame.setSize(</span><span style="color: rgb(0, 0, 0);">300</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">300</span><span style="color: rgb(0, 0, 0);">);<br />        frame.setVisible(</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">);<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> AngelListener </span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);"> ActionListener {<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> actionPerformed(ActionEvent event) {<br />            System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Don't do it, you might regret it!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />        }<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> DevilListener </span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);"> ActionListener {<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> actionPerformed(ActionEvent event) {<br />            System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Come on, do it!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />        }<br />    }<br />}</span></div><br /><br /><br />implement it with java built-in Observe-Pattern<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> java.util.Observable;<br /></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> java.util.Observer;<br />    <br /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> WeatherData </span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);"> Observable {<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> temperature;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> humidity;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> pressure;<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> WeatherData() { }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> measurementsChanged() {<br />        setChanged();<br />        notifyObservers();<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setMeasurements(</span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> temperature, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> humidity, </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> pressure) {<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.temperature </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> temperature;<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.humidity </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> humidity;<br />        </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.pressure </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> pressure;<br />        measurementsChanged();<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> getTemperature() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> temperature;<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> getHumidity() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> humidity;<br />    }<br />    <br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">float</span><span style="color: rgb(0, 0, 0);"> getPressure() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> pressure;<br />    }<br />}<br /></span></div><br /><br /><br /><br /><hr size="2" width="100%" /><br />增加一个看到的通俗版的解说:<br /><br /><strong>观察者模式 Observer Pattern — 三国演义之超级间谍战 — 美女貂蝉的故事</strong><p><strong>说明：</strong>我也是初学者，希望大家能提出宝贵意见。另外转载请注明作者<strong><font color="red">左光</font></strong>和出处<strong><font color="red">博客园</font></strong>，毕竟花费了很长时间才完成。</p><p><strong>情节：</strong></p><p>这一次讲的故事情节很简单，但是充满了谋略和斗争。大体意思就是三国初期，曹刘孙三家在徐州联手消灭了吕布，但是自己也伤了元气。而此时袁术得了传国玉玺，在淮南称帝，兵精将广，图谋不轨，对三家威胁都很大。于是曹刘孙三家在一起开了个会，决定派遣一名<strong>超级间谍</strong>打入到袁术身旁，监视他的一举一动，这样的话一旦袁术想干什么坏事，他们就可以立刻知道并做出相应的调整，知己知彼百战百胜嘛。</p><p>计是好计，问题是派谁去当这个<strong>超级间谍</strong>呢？正当大家愁眉苦脸的时候，美女貂蝉自告奋勇，想当年董卓那么厉害都让
我灭了，何况一个小小的袁术呢？大家一听，说的有理，于是就把貂蝉献给了袁术当了妃子。另外三家还各派出一名小奸细常住在淮南城内，他们的任务是当联络
员，貂蝉有什么情报总不能自己曹刘孙三家挨个跑着送吧？直接丢给各国联络员，然后让他们通知各自的主公就 OK
了！而三家只要一接到各自奸细的通知，就会立即做出反应。</p><p>还有一个小插曲，袁术虽然收下了貂蝉，但是对她看管很严，大大方方地把情报送出去不太可能，逼不得以，貂蝉自己设计了一套密码来传递情报，虽然加密
方法没有公开，但是她想总有人可以破解了吧？没错，对诸葛亮来说就是小菜一碟，从此袁术穿什么内裤曹刘孙三家都知道得清清楚楚。</p><p><strong>分析：</strong></p><p>下面我们用 <strong>观察者模式</strong>  来分析一下上面这个故事</p><p><strong>1、美女貂蝉</strong>：貂蝉在观察者模式中叫做<strong>被观察者（Subject）</strong>，主要任务是独立的管理后台数据和业务逻辑，同时尽可能不受前台客户端界面变化的影响。当然，还要负责登记或者注销各个观察者。</p><p>在这个故事里，貂蝉仅仅维护了一个数据 ，就是情报 —  私有变量 <font color="blue">info</font> ；另外还拥有一个业务逻辑，是用来加密 <font color="blue">info</font> 的方法 <font color="blue">Reverse(<strong>string</strong> str)</font> 。每次得到新的情报，她就会先加密，然后立刻找到在自己这登记过的联络员，让这些联络员通知自己的主公应变。</p><p>情报一旦发送出去， 貂蝉的任务就算完成了，具体曹刘孙三家怎么应对，是打是降还是另有其他方法，那是三家自己的事情，和她貂蝉就没什么关系了。</p><p><strong>2、曹刘孙三家：</strong>曹刘孙三家在观察者模式里叫做<strong>观察者</strong>，主要任务就是从界面上用“各种方式”即时的反映出 <strong>被观察者</strong>，所谓“各种方式”就是说用字符、图形、声音都可以表示同样数据，外在表现不同而已，本质都是一些数据。所谓“即时”，就是说只要 <strong>被观察者 </strong>发生变化， <strong>观察者</strong> 也会立刻跟着变化，用行话应该叫做<strong>刷新 Update</strong>吧。</p><p>在这个故事里，我们可以看到运行结果中，每次貂蝉有什么新的情报，三家都会在屏幕上显示出来，虽然很简单，但<font color="red"> 他们确实是用各自不同的方式表示了同样的数据</font> 。</p><br /><br /><br /><br /><br /><br /><br /><img src ="http://www.blogjava.net/alex/aggbug/62229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-07 20:07 <a href="http://www.blogjava.net/alex/archive/2006/08/07/62229.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之Strategy(策略)</title><link>http://www.blogjava.net/alex/archive/2006/08/01/61238.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 01 Aug 2006 10:26:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/01/61238.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/61238.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/01/61238.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/61238.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/61238.html</trackback:ping><description><![CDATA[先转一篇 jdon的文章:<br /><br /><p>Strategy策略模式是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个个封装成单独的类.</p><p>Stratrgy应用比较广泛,比如, 公司经营业务变化图, 可能有两种实现方式,一个是线条曲线,一个是框图(bar),这是两种算法,可以使用Strategy实现.</p><p>这里以字符串替代为例, 有一个文件,我们需要读取后,希望替代其中相应的变量,然后输出.关于替代其中变量的方法可能有多种方法,这取决于用户的要求,所以我们要准备几套变量字符替代方案.</p><p><img src="http://www.jdon.com/designpatterns/images/Strategy.jpg" height="323" width="443" /></p><p> </p><p>首先,我们建立一个抽象类RepTempRule 定义一些公用变量和方法:</p><table border="0" bordercolor="#cccccc" cellpadding="3" cellspacing="3" width="80%"><tbody><tr><td bgcolor="#cccccc">public abstract class RepTempRule{<br /><br />
                        protected String oldString="";<br />
                        public void setOldString(String oldString){<br />
                        　　this.oldString=oldString; <br />
                        }<br /><br />
                        protected String newString="";<br />
                        public String getNewString(){<br />
                        　　return newString;<br />
                        }<br /><br /><br /><br />
                        public abstract void replace() throws Exception;<br /><br /><br />
                        }</td></tr></tbody></table><p>在RepTempRule中 有一个抽象方法abstract需要继承明确,这个replace里其实是替代的具体方法.<br />
                    我们现在有两个字符替代方案,<br />
                    1.将文本中aaa替代成bbb;<br />
                    2.将文本中aaa替代成ccc;<br /><br />
                    对应的类分别是RepTempRuleOne RepTempRuleTwo</p><table border="0" cellpadding="3" cellspacing="3" width="80%"><tbody><tr><td bgcolor="#cccccc"><p>public class RepTempRuleOne extends 
                          RepTempRule{<br /><br /><br />
                          public void replace() throws Exception{ <br /><br />
                          　　//replaceFirst是jdk1.4新特性 <br />
                          　　newString=oldString.replaceFirst("aaa", 
                          "bbbb") <br />
                          　　System.out.println("this is replace one");<br />
                          　　 <br />
                          }<br /><br /><br />
                          }</p></td></tr></tbody></table><table border="0" cellpadding="3" cellspacing="3" width="80%"><tbody><tr><td bgcolor="#cccccc">public class RepTempRuleTwo extends 
                        RepTempRule{<br /><br /><br />
                        public void replace() throws Exception{ <br /><br />
                        　　newString=oldString.replaceFirst("aaa", "ccc") 
                        <br />
                        　　System.out.println("this is replace Two");<br />
                        　　 <br />
                        }<br /><br /><br />
                        }</td></tr></tbody></table><p>第二步：我们要建立一个算法解决类，用来提供客户端可以自由选择算法。</p><table border="1" width="80%"><tbody><tr><td bgcolor="#cccccc">public class RepTempRuleSolve { <p> 
                          　　private RepTempRule strategy;</p><p> 　　public RepTempRuleSolve(RepTempRule rule){<br />
                          　　　　this.strategy=rule;<br />
                          　　}</p><p> 　　public String getNewContext(Site site,String oldString) 
                          {<br />
                          　　　　return strategy.replace(site,oldString);<br />
                          　　}</p><p> 　　public void changeAlgorithm(RepTempRule newAlgorithm) 
                          {<br />
                          　　　　strategy = newAlgorithm;<br />
                          　　}</p><p>}</p></td></tr></tbody></table><p> </p><p> </p><p>调用如下:</p><table border="0" cellpadding="3" cellspacing="3" width="100%"><tbody><tr><td bgcolor="#cccccc"><p>public class test{</p><p> ......</p><p>　　public void testReplace(){</p><p>　　//使用第一套替代方案<br />
                          　　RepTempRuleSolve solver=new RepTempRuleSolve(new RepTempRuleSimple());<br />
                          　　solver.getNewContext(site,context); </p><p>　　//使用第二套</p><p>　　solver=new RepTempRuleSolve(new RepTempRuleTwo());<br />
                          　　solver.getNewContext(site,context); </p><p>　　}</p><p>.....</p><p>}</p></td></tr></tbody></table><p>我们达到了在运行期间，可以自由切换算法的目的。</p><p>实际整个Strategy的核心部分就是抽象类的使用,使用Strategy模式可以在用户需要变化时,修改量很少,而且快速.</p><p>Strategy和Factory有一定的类似,Strategy相对简单容易理解,并且可以在运行时刻自由切换。Factory重点是用来创建对象。</p><p>Strategy适合下列场合:</p><p>1.以不同的格式保存文件;</p><p>2.以不同的算法压缩文件;</p><p>3.以不同的算法截获图象;</p><p>4.以不同的格式输出同样数据的图形,比如曲线 或框图bar等</p><br /><p>另:<br /></p><p>ahead first design 中的第一篇举例的模型如下<br /></p><br /><img src="http://www.blogjava.net/images/blogjava_net/alex/images/reverse.png" alt="strategy.png" border="0" height="894" width="1111" /><br /><img src ="http://www.blogjava.net/alex/aggbug/61238.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-01 18:26 <a href="http://www.blogjava.net/alex/archive/2006/08/01/61238.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>