<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>sole</title>
    <description>一介书生，纳言耿直，才浅识陋，生无所好，唯偏执于技术。</description>
    <link>http://hex.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>我们为什么要关注MapReduce?</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/235913" style="color:red;">http://hex.javaeye.com/blog/235913</a>&nbsp;
          发表时间: 2008年09月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>1．什么是MapReduce?<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MapReduce&nbsp;是由Google公司的Jeffrey&nbsp;Dean&nbsp;和&nbsp;Sanjay&nbsp;Ghemawat&nbsp;开发的一个针对大规模群组中
的海量数据处理的分布式编程模型。MapReduce实现了两个功能。Map把一个函数应用于集合中的所有成员，然后返回一个基于这个处理的结果集。而
Reduce是把从两个或更多个Map中，通过多个线程，进程或者独立系统并行执行处理的结果集进行分类和归纳。Map()&nbsp;和&nbsp;Reduce()&nbsp;两个
函数可能会并行运行，即使不是在同一的系统的同一时刻。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Google&nbsp;用MapReduce来索引每个抓取过来的Web页面。它取代了2004开始试探的最初索引算法，它已经证明在处理大量和
非结构化数据集时更有效。用不同程序设计语言实现了多个MapReduce，包括&nbsp;Java,&nbsp;C++,&nbsp;Python,&nbsp;Perl,&nbsp;Ruby和C,&nbsp;
其它语言。在某些范例里，如Lisp或者Python,&nbsp;Map()&nbsp;和Reduce()已经集成到语言自身的结构里面。通常，这些函数可能会如下定义：<br />
<br />
List2&nbsp;map(Functor1,&nbsp;List1);<br />
Object&nbsp;reduce(Functor2,&nbsp;List2);<br />
&nbsp;<br />
<br />
Map()函数把大数据集进行分解操作到两个或更多的小&ldquo;桶&rdquo;。而一个&ldquo;桶&rdquo;则是包含松散定义的逻辑记录或者文本行的集合。每个线程，处理器或者系统在独
立的&ldquo;桶&rdquo;上执行Map()函数，去计算基于每个逻辑记录处理的一系列中间值。合并的结果值就会如同是单个Map()函数在单个&ldquo;桶&rdquo;上完全一致。Map
()函数的通常形式是：<br />
<br />
&nbsp;map(function,&nbsp;list)&nbsp;{<br />
&nbsp;&nbsp;foreach&nbsp;element&nbsp;in&nbsp;list&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;v&nbsp;=&nbsp;function(element)<br />
&nbsp;&nbsp;&nbsp;&nbsp;intermediateResult.add(v)<br />
&nbsp;&nbsp;}<br />
}&nbsp;//&nbsp;map<br />
&nbsp;<br />
<br />
Reduce()函数把从内存，磁盘或者网络介质提取过来的一个或多个中间结果列表，对列表中的每个元素逐一执行一个函数。完成操作的最终结果是通过对所有运行reduce()操作的处理结果进行分类和解释。Reduce()函数的通常形式是：<br />
<br />
&nbsp;reduce(function,&nbsp;list,&nbsp;init)&nbsp;{<br />
&nbsp;&nbsp;result&nbsp;=&nbsp;init<br />
&nbsp;&nbsp;foreach&nbsp;value&nbsp;in&nbsp;list&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;function(result,&nbsp;value)<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;outputResult.add(result)<br />
}<br />
MapReduce的实现把业务逻辑从多个处理逻辑中分离出来了，map()和reduce()函数跨越多个系统，通过共享池和部分RPC的形式来达到彼
此之间的同步和通信。这里的业务逻辑是由用户自定义的函数子实现，并且这些函数子只能用在逻辑记录处理的工作上，而不用关心多个处理操作的问题。这样一旦
MapReduce框架就位，就能通过大量的处理器快速的转变为应用系统的并行处理。因为开发人员可以把精力花在写函数子上面了。MapReduce簇可
以通过替换函数子和提供新的数据源来重新使用，而无需每次都对整个应用进行编译，测试和部署。<br />
<br />
2．实现MapReduce<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MapReduce()的目的是为了大型集群的系统能在大数据集上进行并行工作。&nbsp;<br />
<br />
图1显示了一个运行在一个主系统上的主程序，协调其它实例进行map()或者reduce()操作，然后从每个reduce操作中收集结果。<br />
<br />
<img src="http://p.blog.csdn.net/images/p_blog_csdn_net/wildmen/277397/o_%e6%97%a0%e6%a0%87%e9%a2%98.bmp" alt="" />
<br />
【图&nbsp;1】<br />
<br />
主应用程序负责把基础的数据集分解到&ldquo;桶&rdquo;中。桶的最佳大小依赖于应用，结点的数量和可用的I/O带宽。这些&ldquo;桶&rdquo;通常存储在磁盘，但有必要也可能分散到主存中，这依赖于具体的应用。&ldquo;桶&rdquo;将作为map()函数的输入。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;主应用程序也负责调度和分散几个MapReduce的核心备份，除了控制者给空闲的处理器或线程分配了调整map()和reduce()任
务之外，它们是完全相致的。控制者会持续跟踪每个map()和reduce()任务的状态，并且可以作为map()和reduce()任务之间路由中间结
果的管道。每个map()&nbsp;任务处理器完全指派给&ldquo;桶&rdquo;，然后产生一个存到共享存储区域的中间结果集。共享存储可以设计成分布缓存，磁盘或其它设备等形
式。当一个新的中间结果写入共享存储区域后，任务就向控制者发出通知，并提供指向其共享存储位置的句柄。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当新的中间结果可用时，控制者分配reduce()任务。这个任务通过应用独立的中间键值来实现排序，使相同的数据能聚集在一起，以提供更
快的检索。大块的结果集可以进行外部排序，reduce()任务遍历整个排序的数据，把每个唯一的键和分类的结果传递到用户的reduce()&nbsp;函数子进
行处理。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通过map()和reduce()实例终端的处理，当所有的&ldquo;桶&rdquo;都用完，然后全部的reduce()任务就通知控制者，以说明它们的结果已
经产生了。控制者就向主应用程序发出检索这个结果的信号。主应用程序可能就直接操作这些结果，或者重新分配到不同的MapReduce控制者和任务进行进
一步的处理，<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;显示情况下MapReduce的实现可能通常分配给控制者，map()和reduce()任务分配给单独的系统。Google操作模型是基
于跨越大量的廉价硬件设备上组成的集群或者白盒子上面部署MapReduce应用。为了处理它自己的桶的需要，每个白盒子都有本地存储装置，一个合理数量
的私有内存（2到4GB&nbsp;RAM）和至少两个处理内核。白盒子是可互相交换的，主应用程序可能把集群中的任何机器指派为控制者，而这个机器就把map()
和reduce()任务分派给其它连接的白盒子。<br />
<br />
&nbsp;<br />
<br />
3．基于Java的MapReduce&nbsp;实现<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Google的环境是为它自己的需求定制和适应它们的操作环境。比如，为了它的MapReduce实现更好的执行这种类型的操作，使其更优
化，Google使用了专有的文件系统用来存储文件。相反，企业应用系统都是建立在Java或类似的技术上面的，它们依赖于已有的文件系统，通信协议和应
用栈。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个基于Java的MapReduce实现应该考虑到已存在的数据存储设备，将来部署到的结构里面支持那种协议，有哪些内部API和支持部署那种第三方产品（开源的或商业的）。图2显示了通常的架构是如何通过映射到已有的、健壮的Java开源架构来实现的。<br />
<br />
<img src="http://p.blog.csdn.net/images/p_blog_csdn_net/wildmen/277397/o_%e6%97%a0%e6%a0%87%e9%a2%982.bmp" alt="" />
<br />
【图&nbsp;2】<br />
<br />
这个架构采用了已有的工具，比如Terracotta和Mule，它们经常出现在很多企业系统的组织里面。已物理或虚拟系统形成存在的白盒子通过有效简单
的配置和部署，设计成MapReduce群组中的一部分。为了效率，一个很大的系统可以分解到几个虚拟机器上，如果需要可以分配更多的结点。可以根据容量
的问题和处理器的有效利用赖决定是否在群集中使用物理&ldquo;白盒子&rdquo;，虚拟机或者它们两者的结合。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Terracotta&nbsp;集群技术是map()和reduce()任务之间共享数据的很好选择，因为它把map()和reduce()之间的通信过程，包括共享文件或者使用RPC调用已初始处理结构都做了抽象。<br />
<br />
从前面章节的描述知道，Map()和reduce()任务是在同一个核心应用中实现的。用来共享中间结构集的数据结构可以保持在内存的数据结构中，通过Terracotta透明的共享交换。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由跨域集群的MapReduce产生的进程内通信问题，自从Terracotta运行时掌管着这些共享数据结构后就不存在了。不同于实现一个复杂的信号系统，所有的map()任务需要标记内存中的中间结构集，然后reduce()任务就直接提取它们。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;控制者和主应用程序都会在同时处在等待状态一段时间，即使是MapReduce集群有大量可用的并行处理能力。这两个组件之间以及当归并完
成后的reduce()任务和控制者之间，都是通过Mule的ESB传递信号的。通过这种方式，为了其它应用的处理，输出结构可以排到队列，或者像前面章
节讲的一样，为了其他MapReduced的处理，一个Mule服务对象（or&nbsp;UMO）可以把这些输出结果分解到&ldquo;桶&rdquo;中。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通过主流的企业应用协议或者完全的原始TCP/IP&nbsp;Sockets，Mule支持在内存中进行同步和异步的数据传输.&nbsp;Mule可以用于
在同一台机器执行的应用系统，跨域不同的数据中心或者在完全不同地方且被程序员分开标识的本地终端结点互相传递输出结构集。其它基于Java的实现可以通
过Hadoop,&nbsp;是一个用于运行应用程序在大型集群的廉价硬件设备上的框架，&nbsp;它是基于lucene框架。Hadoop是一个开源，点对点，通用的
MapReduce实现。<br />
<br />
&nbsp;<br />
<br />
4.结论<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不管使用什么技术，索引大量非结构化数据是一件很艰难的任务。应用传统的算法和启发式方法很难维护，因为随着时间的推移，系统的性能下降使
系统变得难以控制。RDBMS&nbsp;能有效的用于索引和检索大量的结构化数据集合，但不适合用于非结构化的数据。MapReduce为并行系统的数据处理，提
供了一个简单，优雅的解决方案，优势有：<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;归并成本<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;程序员的高产出，因为用并行的代码独立实现了业务逻辑<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;比传统RDBMS技术更好的性能和更优的结果。<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用Java企业框架和开发着都熟悉的已有的技术和工具赖更易部署<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;用MapReduce,&nbsp;Google有令人印象深刻的跟踪记录，而且每天出现的工具都能轻易的融入到这个体系中。在企业级的应用系统中，如果你
准备开始一个快速，简单的任务，例如根据IP地址分析请求的拥堵模型到你的web集群中，或者类似的东西。一个这样的练习将会很大程度上提高你对关键系统
面临的问题和挑战的认识,MapReduce则就是为这些而准备的。<br />
<br />
&nbsp;<br />
<br />
英文原址：http://www.theserverside.com/tt/knowledgecenter-tc/knowledgecenter-tc.tss?l=MapReduce</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/235913#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 02 Sep 2008 21:57:22 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/235913</link>
        <guid>http://hex.javaeye.com/blog/235913</guid>
      </item>
      <item>
        <title> 关于http的Last-Modified和ETag</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/235827" style="color:red;">http://hex.javaeye.com/blog/235827</a>&nbsp;
          发表时间: 2008年09月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp; 1)&nbsp;什么是&rdquo;Last-Modified&rdquo;?&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在浏览器第一次请求某一个URL时，服务器端的返回状态会是200，内容是你请求的资源，同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间，格式类似这样：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Last-Modified:&nbsp;Fri,&nbsp;12&nbsp;May&nbsp;2006&nbsp;18:53:33&nbsp;GMT&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;客户端第二次请求此URL时，根据&nbsp;HTTP&nbsp;协议的规定，浏览器会向服务器传送&nbsp;If-Modified-Since&nbsp;报头，询问该时间之后文件是否有被修改过：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If-Modified-Since:&nbsp;Fri,&nbsp;12&nbsp;May&nbsp;2006&nbsp;18:53:33&nbsp;GMT&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果服务器端的资源没有变化，则自动返回&nbsp;HTTP&nbsp;304&nbsp;（Not&nbsp;Changed.）状态码，内容为空，这样就节省了传输数据量。
当服务器端代码发生改变或者重启服务器时，则重新发出资源，返回和第一次请求时类似。从而保证不向客户端重复发出资源，也保证当服务器有变化时，客户端能
够得到最新的资源。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)&nbsp;什么是&rdquo;Etag&rdquo;?&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HTTP&nbsp;协议规格说明定义ETag为&ldquo;被请求变量的实体值&rdquo;&nbsp;（参见&nbsp;&mdash;&mdash;&nbsp;章节&nbsp;14.19）。&nbsp;另一种说法是，ETag是一个可以
与Web资源关联的记号（token）。典型的Web资源可以一个Web页，但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义，并
在HTTP响应头中将其传送到客户端，以下是服务器端返回的格式：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ETag:&nbsp;&quot;50b1c1d4f775c61:df3&quot;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;客户端的查询更新格式是这样的：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If-None-Match:&nbsp;W/&quot;50b1c1d4f775c61:df3&quot;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果ETag没改变，则返回状态304然后不返回，这也和Last-Modified一样。本人测试Etag主要在断点下载时比较有用。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Last-Modified和Etags如何帮助提高性能?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;聪明的开发者会把Last-Modified&nbsp;和ETags请求的http报头一起使用，这样可利用客户端（例如浏览器）的缓存。因为服
务器首先产生&nbsp;Last-Modified/Etag标记，服务器可在稍后使用它来判断页面是否已经被修改。本质上，客户端通过将该记号传回服务器要求服
务器验证其（客户端）缓存。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;过程如下:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;客户端请求一个页面（A）。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;服务器返回页面A，并在给A加上一个Last-Modified/ETag。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.&nbsp;客户端展现该页面，并将页面连同Last-Modified/ETag一起缓存。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.&nbsp;客户再次请求页面A，并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.&nbsp;服务器检查该Last-Modified或ETag，并判断出该页面自上次客户端请求之后还未被修改，直接返回响应304和一个空的响应体。</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/235827#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 02 Sep 2008 17:05:27 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/235827</link>
        <guid>http://hex.javaeye.com/blog/235827</guid>
      </item>
      <item>
        <title>Http的一些编码</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/235367" style="color:red;">http://hex.javaeye.com/blog/235367</a>&nbsp;
          发表时间: 2008年09月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2>HTTP Headers</h2>
<p>The headers of a HTTP request or response must be in <tt>US-ASCII</tt>
 format.
        It is not possible to use non <tt>US-ASCII</tt>
 characters in the header of a
        request or response.  Generally this is not an issue however, because the
        HTTP headers are designed to facilite the transfer of data rather than to
        actually transfer the data itself.</p>
<p>One exception however are cookies. Since cookies are transfered as HTTP Headers
        they are confined to the <tt>US-ASCII</tt>
 character set. See the Cookie Guide
        for more information.
      </p>
<div class="section"><a name="Request_Response_Body"></a>
<h2>Request/Response Body</h2>
<p>The request or response body can be any encoding, but by default is
        <tt>ISO-8859-1</tt>
.  The encoding may be specified in the 
        <tt>Content-Type</tt>
 header, for example:
        </p>
<blockquote>Content-Type: text/html; charset=UTF-8</blockquote>
<p>In this case the application should be careful to use UTF-8 encoding
      when converting the body to a String or some characters may be corrupt.
      You can set the content type header for a request with the
      <code>addRequestHeader</code>
 method in each method and retrieve the
      encoding for the response body with the <code>getResponseCharSet</code>
      method.</p>
<p>If the response is known to be a String, you can use the
      <code>getResponseBodyAsString</code>
 method which will automatically use
      the encoding specified in the <tt>Content-Type</tt>
 header or 
      <tt>ISO-8859-1</tt>
 if no charset is specified.</p>
<p>Note that some document types, such as HTML and XML allow the author
      to specify the content type of the file.  In this case, you should
      consult the appropriate standards regarding how to resovle any conflicts
      in the reported charsets.</p>
</div>
<div class="section"><a name="URLs"></a>
<h2>URLs</h2>
<p>The standard for URLs (<a href="http://www.ietf.org/rfc/rfc1738.txt" title="External Link" class="externalLink">RFC1738</a>
) explictly
      states that URLs may only contain graphic printable characters of the
      <tt>US-ASCII</tt>
 coded character set and is defined in terms of octets.
      The octets <code>80-FF</code>
 hexadecimal are not used in <tt>US-ASCII</tt>
 and the octets
      <code>OO-1F</code>
 hexadecimal represent control characters; characters in these
      ranges must be encoded.</p>
<p>Characters which cannot be represented by an 8-bit ASCII code, can not
      be used in an URL as there is no way to reliably encode them (the
      encoding scheme for URLs is based off of octets).  Despite this, some
      servers do support varying means of encoding double byte characters in
      URLs, the most common technique seems to be to use UTF-8 encoding and
      encode each octet separately even if a pair of octets represents one
      character.  This however, is not specified by the standard and is highly
      prone to error, so it is recommended that URLs be restricted to the 8-bit
      ASCII range.</p>
</div>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/235367#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 01 Sep 2008 15:43:47 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/235367</link>
        <guid>http://hex.javaeye.com/blog/235367</guid>
      </item>
      <item>
        <title>Java并发库的设计模式---Command模式</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/232901" style="color:red;">http://hex.javaeye.com/blog/232901</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">public interface Executor{
      void execute(Runnable cmd);
}</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如此简单的接口，却为一个灵活而强大的框架创造了基础。使得线程的执行逻辑和时序逻辑得到了分离，提高了健壮性和可扩张性，使得需求变化时不再是将整个程序重写而只需修改相应的执行逻辑</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; Executor解藕了任务的执行策略和任务的执行过程:&nbsp; 只要提交给Executor一个Runnable，Exector根据自身的执行策略（如使用线程池，定时执行，或单线程等等），去调用runnable的run方法。Executor只是指定执行的策略，只知道Runnable有个run方法，不需要知道run what；而 Runnable只需要知道自己到底做什么，不需要知道到底按什么顺序做，什么时刻做。</p>
<p>&nbsp;&nbsp; &nbsp;&nbsp; 这里面有两个变化点：<span style="color: #008000;">&ldquo;做什么&rdquo; 和 &rdquo;怎么做&ldquo;的变化</span>
。<span style="color: #ff0000;">当系统有多个变化点时，我们一般的做法是对每个变化点分别进行封装</span>
。这样使得每个对象（类）只需要管理一种变化。一个变化了，不会影响到其他的变化点，保证了可扩展性。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Executor实际上就是一个Command模式。命令模式使用很常见，GUI的Swing中菜单命令，JDBC的Query命令对象等等(这里不说Command模式了,想写的时候在写吧）。</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类库中提供了几个Executor的实现(主要用于线程池)，通过调用Executors的某个静态方法来创建：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newFixedThreadPool 创建一个顶长的线程池。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newCacheThreadPoo; 创建一个可缓存的线程池。如果当前线程池的长度超过了处理的需要，就回收空闲线程；当需求增加是，灵活增加新的线程。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newSingleThreadExecutor 创建一个单线程的executor</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newScheduleThreadPool 创建一个定长的线程池，支持定时的以及周期性的执行（替代Timer）</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="quote_title">Executor Vs Thread </div>
<div class="quote_div">当看到如下的代码：<br />
new Thread(runnable).start()<br />
并且可能最终希望获得一个更加灵活的执行策略是，考虑使用Executor代替Thread</div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp; ExecutorService继承了Executor，提供了对生命周期管理。</p>
<p>&nbsp;</p>
<pre name="code" class="java">public interface ExecutorService exetends Executor {
     void shutdown(();
     List&lt;Runnable&gt; shutdownNow();
     boolean isShutdown();
     boolean istermindated();
    boolean awaitTermination(long timeout, TimeUnit unit)
        throw InterruptedException;
    //....其他用于任务提交的便利方法
}</pre>
&nbsp;
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/232901#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 16:29:34 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/232901</link>
        <guid>http://hex.javaeye.com/blog/232901</guid>
      </item>
      <item>
        <title>面向对象设计原则</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/232217" style="color:red;">http://hex.javaeye.com/blog/232217</a>&nbsp;
          发表时间: 2008年08月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>OO设计根本的指导原则是提高可维护性和可复用性。这些原则主要有：
</p>
<p>1.单一职责原则
    </p>
<p style="padding-left: 30px;">就一个类而言，应该仅有一个引起它的变化的原因</p>
<p>最简单，最单纯的事情最容易控制，最有效</p>
<p>
    类的职责简单而且集中，避免相同的职责分散到不同的类之中，避免一个类承担过多的职责</p>
<p>
2. 开闭原则
</p>
<p>一个软件实体（类，模块或组件）应该对扩展开放，对修改关闭。
</p>
<p style="padding-left: 30px;">在设计一个模块的时候，就当使这个模块可以在不被修改的前提下被扩展。换言之，就当可以在不必修改源代码的情况下改变这个模块的行为。</p>
<p>
3. 依赖倒转原则
</p>
<p>依赖倒转原则讲的是：要依赖于抽象，不要信赖于实现。
</p>
<p>开闭原则是目标，而达到这一目标的手段是依赖倒转原则
</p>
<p>4. 里氏代换原则
</p>
<p style="padding-left: 30px;">任何基类可以出现的地方，子类一定可以出现。
</p>
<p>5. 合成/聚合复用原则
</p>
<p style="padding-left: 30px;">要尽量使用合成/聚合，而不是继承关系达到复用的目的。
</p>
<p>6. 迪米特原则
</p>
<p style="padding-left: 30px;">一个软件实体应当尽可能少的其他实体发生相互作用。模块之间的交互要少。这样做的结果是当系统的功能需要扩展时，会相对更容易地做到对修改的关闭。
</p>
<p style="padding-left: 30px;">一个对象应当对其他对象有尽可能少的了解。
</p>
<p>7. 接口隔离原则
</p>
<p style="padding-left: 30px;">应当为客户端提供尽可能小的单独接口，而不要提供大的总接口。</p>
<p style="padding-left: 30px;">也即是使用多个专门的接口比使用单一的总接口要好。
</p>
<p>&nbsp;</p>
<p>几句经典话：</p>
<p>优先考虑使用组合，而不是继承;</p>
<p>
对扩展开放，对修改封闭；</p>
<p>
面向接口编程，而不要面对实现编程；</p>
<p>
一个对象只负有一种责任；</p>
<p>
Don't call me, I Will call you.</p>
<p>&nbsp;</p>
<p>以上原则不必严格遵守，但是在设计编程是时应拿此参考。总之，目的是使设计最明了，最简单（个人意见）</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/232217#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 25 Aug 2008 09:40:47 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/232217</link>
        <guid>http://hex.javaeye.com/blog/232217</guid>
      </item>
      <item>
        <title>分布式Web爬虫的设计</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/230633" style="color:red;">http://hex.javaeye.com/blog/230633</a>&nbsp;
          发表时间: 2008年08月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>URL管理服务器（URL-Server）：负责url的集中管理，不详细讨论<br />
爬虫(Crawler):&nbsp;  从Server中取得一个url后，下载页面，提取链接，提取文本后保存。</p>
<p>&nbsp;</p>
<p>爬虫的设计：</p>
<p>两个producer-consumer队列：URL的本地存取队列(CrawlURLQueue)和新产生的url缓存队列（NewURLQueue）. </p>
<p>爬虫监控CrawlURLQueue队列当前的容量，当url减少到一定数目后，就向URL-Server中批量请求URL，并插入到CrawlURLQueue队列中；</p>
<p>每个爬虫从队列中取出url，提取链接,并把新产生的url插入到NewURLQueue；</p>
<p>当NewURLQueue到达一定容量后（或定时），提交给URL-Server</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img src="../../../upload/attachment/35504/806c8db3-da63-3ab9-81d6-54422d75468e.jpg" height="457" alt="Crawler" width="543" />
</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>线程：</p>
<p>1.CrawlURLQueue生产者线程,向URL-Server请求新的URL</p>
<p>2.CrawlURLQueue消费者线程，实际的爬虫线程个数(n)，视机器性能而定</p>
<p>3.提取URL和正文线程</p>
<p>5,NewURLQueue消费者线程，提交到URL-Server</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/230633#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 20 Aug 2008 11:55:55 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/230633</link>
        <guid>http://hex.javaeye.com/blog/230633</guid>
      </item>
      <item>
        <title>Java 5.0的多线程类或接口</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/230222" style="color:red;">http://hex.javaeye.com/blog/230222</a>&nbsp;
          发表时间: 2008年08月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>Executor</p>
<p>ExecutorService</p>
<p>Callable&lt;V&gt;</p>
<p>Future&lt;V&gt;</p>
<p>CompletionService</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>同步器：</p>
<p>CountDownLatch</p>
<p>FutureTask&lt;V&gt;</p>
<p>Semaphore</p>
<p>CyclicBarrier</p>
<p>&nbsp;</p>
<p>并发容器：</p>
<p>ConcurrentHashMap</p>
<p>CopyOnWriteArrayList</p>
<p>BlockingQueue</p>
<p>ConcurrentLinkedQueue</p>
<p>PriorityQueue</p>
<p>&nbsp;</p>
<p>有时间在说说他们的功能，和提供些sample</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/230222#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 19 Aug 2008 17:49:28 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/230222</link>
        <guid>http://hex.javaeye.com/blog/230222</guid>
      </item>
      <item>
        <title>JDK5.0 Excutor创建线程池</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/230183" style="color:red;">http://hex.javaeye.com/blog/230183</a>&nbsp;
          发表时间: 2008年08月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolTest {

	public static void main(String[] args) {
		final ExecutorService exec = Executors.newFixedThreadPool(3);
		
		for(int i=1; i&lt;=10; ++i){
			Runnable r = new Task(i);
			exec.execute(r);
		}
		exec.shutdown();
	}

	static class Task implements Runnable {
		private int id;

		Task(int id) {
			this.id = id;
		}

		public void run() {
			try {
				System.out.println(id + &quot; Start&quot;);
				Thread.sleep(500);
				System.out.println(id + &quot; Do&quot;);
				Thread.sleep(500);
				System.out.println(id + &quot; Exit&quot;);
			} catch (Exception e) {
				Thread.currentThread().interrupt();
			}
		}

	}

}
</pre>
&nbsp;
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/230183#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 19 Aug 2008 16:11:22 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/230183</link>
        <guid>http://hex.javaeye.com/blog/230183</guid>
      </item>
      <item>
        <title>敏捷开发</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/229880" style="color:red;">http://hex.javaeye.com/blog/229880</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>敏捷开发</h1>
<p>&nbsp;</p>
<div>
<p align="right"><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="color: #f70938;"><span style="font-family: 黑体;"><a href="http://www.itisedu.com/phrase/200604112229525.html" target="_new"><br />
</a>
</span>
<span style="font-family: 黑体;">
</span>
</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.itisedu.com/phrase/200603291800375.html" target="_new">敏捷开发</a>
（<a href="http://www.itisedu.com/phrase/200604240917025.html" target="_new">agile development</a>
）是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中，<a href="http://www.itisedu.com/phrase/200604232134205.html" target="_new">软件</a>
项目的构建被切分成多个子项目，各个子项目的成果都经过测试，具备集成和可运行的特征。简言之，就是把一个大项目分为多个相互联系，但也可独立运行的小项目，并分别完成，在此过程中软件一直处于可使用状态。</span>
</p>
<p><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 敏捷开发是全新理论吗？答案莫衷一是。细心的人们可以发现，敏捷开发其实借鉴了大量<a href="http://www.itisedu.com/phrase/200602281725525.html" target="_new">软件工程</a>
中的方法。迭代与增量开发，这两种在任何一本软件工程教材中都会被提到的方法，在敏捷开发<a href="http://www.itisedu.com/phrase/200603061709535.html" target="_new">模式</a>
中扮演了很重要的角色。再向前追溯，我们还也可见到瀑布式与快速原型法的影子，也许还有更多。</span>
</p>
<p><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 改善，而非创新。敏捷开发可理解为在原有<a href="http://www.itisedu.com/phrase/200603282233345.html" target="_new">软件开发</a>
方法基础上的整合&mdash;&mdash;取其精华，去其糟粕。因此敏捷开发继承了不少原有方法的优势。&ldquo;在敏捷软件开发的过程中，我们每两周都会得到一个可以工作的软件，&rdquo;Fowler介绍，&ldquo;这种非常短的循环，使终端客户可以及时、快速地看到他们花钱构建的软件是一个什么样的结果。&rdquo;</span>
</p>
<p><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也许是因为时间关系，Fowler只说出了这些优势中的一部分。允许开发过程中的<a href="http://www.itisedu.com/phrase/200603101518295.html" target="_new">需求</a>
变化、通过早期迭代可以较早发现风险、使代码重用变得可行、减少项目返工&hellip;&hellip;借鉴了众多先进方法和丰富经验，拥有的众多优势使得敏捷开发看来已经成为解决<a href="http://www.itisedu.com/phrase/200603112323405.html" target="_new">软件危机</a>
的标准答案。</span>
</p>
<p><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 问题与思考<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然而，我们不得不面对的现实却是，模式与方法的优化并不意味着问题的终结。作为一种开发模式，敏捷开发同样需要面对众多挑战。</span>
</p>
<p><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
大项目的拆分意味着更多子项目的出现，协调这些同步或异步推进的子项目，合理的资源调配都将变得更加复杂。另外，在当前项目和项目组普遍&ldquo;增容&rdquo;的情况
下，遇到的问题同样成倍增长。人的重要性被提到了更高的高度，而缺乏有效协调手段，减少人员流动和项目变更对整个项目造成的影响也将成为一大挑战&hellip;&hellip;新方
法带来众多便利的同时，也相应引发了几乎同样多的问题。</span>
</p>
<p>&nbsp;</p>
<span style="font-family: Verdana;">
</span>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 敏捷开发（<a href="http://www.itisedu.com/phrase/200604240943515.html" target="_new">agile</a>
 development）概念从2004年初开始广为流行。Bailar非常支持这一理论，他采取了&quot;敏捷方式&quot;组建<a href="http://www.itisedu.com/phrase/200603082251135.html" target="_new">团队</a>
：Capital
One的&quot;敏捷团队&quot;包括3名业务人员、两名操作人员和5～7名IT人员，其中包括1个业务信息指导（实际上是业务部门和IT部门之间的&quot;翻译者&quot;）；另
外，还有一个由项目经理和至少80名开发人员组成的团队。这些开发人员都曾被Bailar送去参加过&quot;敏捷开发&quot;的培训，具备相关的技能。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
每个团队都有自己的敏捷指导（Bailar聘用了20个敏捷指导），他的工作是关注流程并提供建议和支持。最初提出的需求被归纳成一个目标、一堆记录详细
需要的卡片及一些供参考的原型和模板。在整个项目阶段，团队人员密切合作，开发有规律地停顿--在9周开发过程中停顿3～4次，以评估过程及决定需求变更
是否必要。在Capital
One，大的IT项目会被拆分成多个子项目，安排给各&quot;敏捷团队&quot;，这种方式在&quot;敏捷开发&quot;中叫&quot;蜂巢式（swarming）&quot;，所有过程由一名项目经理
控制。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了检验这个系统的效果，Bailar将项目拆分，从旧的&quot;瀑布式&quot;开发转变为&quot;并列式&quot;开发，形成了&quot;敏捷开发&quot;所倡导的精干而灵活的开发团队，并将开发阶段分成30天一个周期，进行&quot;冲刺&quot;--每个冲刺始于一个启动会议，到下个冲刺前结束。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
在Bailar将其与传统的开发方式做了对比后，他感到非常兴奋--&quot;敏捷开发&quot;使开发时间减少了30%～40%，有时甚至接近50%，提高了交付产品的
质量。&quot;不过，有些需求不能用敏捷开发来处理。&quot;
Bailar承认，&quot;敏捷开发&quot;也有局限性，比如对那些不明确、优先权不清楚的需求或处于&quot;较快、较便宜、较优&quot;的三角<a href="http://www.itisedu.com/phrase/200604241328115.html" target="_new">架构</a>
中却不能排列出三者优先级的需求。此外，他觉得大型项目或有特殊规则的需求的项目，更适宜采用传统的开发方式。尽管描述需求一直是件困难的事，但经过阵痛之后，需求处理流程会让CIO受益匪浅。</span>
</span>
</p>
<span style="font-family: Verdana;"><span style="font-family: Verdana;">
</span>
</span>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 敏捷开发是由一些业界专家针对一些企业现状提出了一些让软件开发团队具有快速工作、响应变化能力的价值观和原则，并于2001初成立了敏捷联盟。他们正在通过亲身实践以及帮助他人实践，揭示更好的软件开发方法。通过这项工作，他们认为： </span>
</span>
</p>
<ul>
<span style="font-family: Verdana;"><span style="font-family: Verdana;">
<li>个体和交互 胜过 过程和工具 
</li>
<li>可以工作的软件 胜过 面面俱到的文档 
</li>
<li>客户合作 胜过 合同谈判 
</li>
<li>响应变化 胜过 遵循计划 </li>
</span>
</span>

</ul>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">并提出了以下遵循的原则： </span>
</span>
</p>
<ul>
<span style="font-family: Verdana;"><span style="font-family: Verdana;">
<li>我们最优先要做的是通过尽早的、持续的交付有价值的软件来使客户满意。 
</li>
<li>即使到了开发的后期，也欢迎改变需求。敏捷过程利用变化来为客户创造竞争优势。 
</li>
<li>经常性地交付可以工作的软件，交付的间隔可以从几个星期到几个月，交付的时间间隔越短越好。 
</li>
<li>在整个项目开发期间，业务人员和开发人员必须天天都在一起工作。 
</li>
<li>围绕被激励起来的个体来构建项目。给他们提供所需的环境和支持，并且信任他们能够完成工作。 
</li>
<li>在团队内部，最具有效果并富有效率的传递信息的方法，就是面对面的交谈。 
</li>
<li>工作的软件是首要的进度<a href="http://www.itisedu.com/phrase/200604231331545.html" target="_new">度量</a>
标准。 
</li>
<li>敏捷过程提倡可持续的开发速度。责任人、开发者和用户应该能够保持一个长期的、恒定的开发速度。 
</li>
<li>不断地关注优秀的技能和好的设计会增强敏捷能力。 
</li>
<li>简单是最根本的。 
</li>
<li>最好的构架、需求和设计出于自组织团队。 
</li>
<li>每隔一定时间，团队会在如何才能更有效地工作方面进行反省，然后相应地对自己的行为进行调整。 </li>
</span>
</span>

</ul>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><strong>一、敏捷开发方法</strong>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">（一） 说明 <br />
本文是阅读Alistair Cockburn的Agile Software Development和William C. Wake的<a href="http://www.itisedu.com/phrase/200604231325145.html" target="_new">XP</a>
 Explored的一些笔记和想法，Agile Software Development是一组软件开发方法的总称，包括（Crystal , <a href="http://www.itisedu.com/phrase/200604231325295.html" target="_new">Extreme Programming</a>
 , Adaptive software development等等）。敏捷开发方法又称为&ldquo;轻量级&rdquo;开发方法。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">下面这段话摘自Martin Fowler的一篇文章：</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">从无到繁重再到敏捷<br />
多数软件开发仍然是一个显得混
乱的活动，即典型的&ldquo;边写边改&rdquo; （code and
fix）。设计过程充斥着短期的，即时的决定，而无完整的规划。这种模式对小系统开发其实很管用，但是当系统变得越大越复杂时，要想加入新的功能就越来越
困难。同时错误故障越来越多，越来越难于排除。一个典型的标志就是当系统功能完成后有一个很长的测试阶段，有时甚至有遥遥无期之感，从而对项目的完成产生
严重的影响。 <br />
我们使用这种开发模式已有很长时间了，不过我们实际上也有另外一种选择，那就是&ldquo;正规方法&rdquo;（methodology）。这些方法对开发过程有着严格而详尽的规定，以期使软件开发更有可预设性并提高效率，这种思路是借鉴了其他工程领域的实践。 <br />
这
些正规方法已存在了很长时间了，但是并没有取得令人瞩目的成功，甚至就没怎么引起人们的注意。对这些方法最常听见的批评就是它们的官僚繁琐，要是按照它的
要求来，那有做太多的事情需要做，而延缓整个开发进程。所以它们通常被认为是&ldquo;繁琐滞重型&rdquo;方法，或Jim HighSmith
所称的&ldquo;巨型&rdquo;（monumental)方法。 <br />
作为对这些方法的反叛，在过去几年中出现了一<a href="http://www.itisedu.com/phrase/200603090857555.html" target="_new">类</a>
新方法。尽管它们还没有正式的名称，但是一般被称为&ldquo;敏捷型&rdquo;方法。对许多人来说，这类方法的吸引之处在于对繁文缛节的官僚过程的反叛。它们在无过程和过于繁琐的过程中达到了一种平衡，使得能以不多的步骤过程获取较满意的结果。 <br />
敏捷型与滞重型方法有一些显著的区别。其中一个显而易见的不同反映在文档上。敏捷型不是很面向文档，对于一项任务，它们通常只要求尽可能少的文档。从许多方面来看，它们更象是&ldquo;面向源码&rdquo;（code-oriented）。事实上，它们认为最根本的文档应该是源码。 <br />
但是，我并不以为文档方面的特点是敏捷型方法的根本之点。文档减少仅仅是个表象，它其实反映的是更深层的特点： <br />
?
敏捷型方法是&ldquo;适配性&rdquo;而非&ldquo;预设性&rdquo;。
重型方法试图对一个软件开发项目在很长的时间跨度内作出详细的计划，然后依计划进行开发。这类方法在计划制定完成后拒绝变化。而敏捷型方法则欢迎变化。其
实，它们的目的就是成为适应变化的过程，甚至能允许改变自身来适应变化。 <br />
? 敏捷型方法是&ldquo;面向人&rdquo;的(people-oriented) 而非&ldquo;面向过程&rdquo;的 (process-oriented)。 它们试图使软件开发工作顺应人的天性而非逆之。它们强调软件开发应当是一项愉快的活动。 <br />
我认为以上两个特点很好的概括了敏捷开发方法的核心思想：适应变化和以人为中心</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">（二） 方法背后的思想</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">Alistair Cockburn在Agile Software Development中讲述了敏捷开发方法背后的思想</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">人们掌握过程（process）可以分为3个阶段：<br />
1 following 遵循一个定义好的process<br />
2 detaching 知道不同process的适用范围，在不同的场合使用不同的process<br />
3 fluent 不关心是否遵循特定的process，知道在什么情况下采用什么动作</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">软件开发是一个充满发明和交流的协作性游戏
(cooperative game of invertion and
communication)。软件开发的首要目标是生产出软件，遵循特定的过程和模型只是手段，只要传递了足够的信息，手段是次要的。交流的效果要远远
重于交流的形式（Effect of communication is more important than the form of
communication）。<br />
一般软件开发有两个目标：1 尽快的生产出软件2 为下一个<a href="http://www.itisedu.com/phrase/200604231345425.html" target="_new">team</a>
或项目做准备，有时这两个目标是矛盾的，我们要在这两个目标之间寻求平衡</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">在软件开发中，人的因素要远远大于过程和技术。人是有缺陷的：<br />
1 容易犯错误，因此必须在错误扩散之前找到并改正错误<br />
2 当觉得可能失去较多的时候，不愿意冒险<br />
3 重新构造而不愿意重复使用已有的东西<br />
4 难于坚持一个习惯</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">针对个人因素的几个建议：<br />
1 具体的模型较抽象的模型更容易理解<br />
2 从一个例子开始是容易的<br />
3 通过观察他人的成果学习<br />
4 要有足够的不受打扰的时间<br />
5 分配的工作要与个人意向，能力匹配<br />
6 不正确的奖励会有坏作用，从长期看个人兴趣比奖励更重要，培养在工作中的自豪感：<br />
1) pride in work参与工作的自豪感，通常参与一个重要的工作会有自豪感<br />
2) pride in accomplishment 完成工作的自豪感，长期未完的工作会使士气低落<br />
3)pride in contribution 为他人贡献的自豪感<br />
7 鼓励关心其他人的工作和整体的工作</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">在一个团队之间，交流是最重要的，实践证明面对面的实时的交流是最有效的，对交流的延误会损失信息，白板是最好的交流工具，交流工具的先进并不能提高交流效果。文档的作用是记录和备忘，不能通过文档交流。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">敏捷开发方法要避免的过程设计的几个常见错误<br />
1 对所有的项目使用同一种过程<br />
2 没有弹性<br />
3 过于沉重<br />
4 增加不必要的&ldquo;必须完成&rdquo;（&ldquo;should do&rdquo; is really should？）<br />
5 没有经过实践检验</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">敏捷开发方法过程设计的几个原理：<br />
1 交互的面对面的交流是代价最小，最迅速的交换信息的方法<br />
2 超过实际需要的过程是浪费的<br />
3 大的团队需要重量级方法<br />
4 处理重大问题的项目需要重量级方法强调<br />
5 增加反馈和交流可以减少中间产品和文档的需求<br />
6 轻量级方法更强调理解（understanding）,自律（discipline）和技能(skill)，重量级方法更强调文档（documentation），过程（process）和正式（formality）<br />
understanding指整个团队关于项目的全部知识，包括讨论的过程，documentation只能记录其中的一部分<br />
discipline是指个人主动的完成工作，process指个人根据指令完成工作<br />
skill指具有良好技能的人可以省略中间的产品，formality指必须按照规定步骤完成工作</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">7 确定开发中间的瓶径，提高它的效率<br />
对于瓶径处的工作应该尽量加快，减少重复，（使用更熟练的人，使用更多的人，使用更好的工具，使瓶径处的工作的深入尽量稳定）对于非瓶径处的工作可以多一些重复，在输入还不确定的情况下也可以尽早开始。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">这些原理的几个结论：<br />
1 向一个项目增加人员要花费较大代价（constly），因为原有人员和新人员之间的交流要花费大量时间<br />
2 团队的规模经常是跳跃的，例子：需要6个熟练的<a href="http://www.itisedu.com/phrase/200604232224305.html" target="_new">程序</a>
员，但是只有4个，于是增加不熟练的程序员，结果团队的大量时间花费在培训不熟练的程序员上面，最后增加到了20个不熟练的程序员。<br />
3 应该侧重于提高团队的技能而不是扩充团队<br />
4 对不同的项目使用不同的过程<br />
5 在适用的条件下，轻量级的方法优于重量级的方法<br />
6 对不同的项目要裁减过程</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">敏捷开发方法的原则是&ldquo;刚刚好&rdquo;（Light and Sufficient）</span>
</span>
</p>
<span style="font-family: Verdana;"><span style="font-family: Verdana;">
</span>
</span>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
（三） Crystal</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">Crystal是Alistair
Cockburn提出的一组开发方法，分为Crystal Clear,Crystal Yellow, Crystal
Orange和Crystal Red分别适用于不同的项目。项目可以按照参加的人员和重要性划分。重要性根据项目中的错误引发的后果分为：<br />
C Loss of comfort （某些不舒适）<br />
D Loss of discretionary money (经济损失)<br />
E Loss of Essential Money (严重经济损失)<br />
L Life Critical (生命危险)<br />
一个项目称为C6说明参加人员在6人以下，重要性是C级，D20说明人员在6-20人，重要性是D级。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">Crystal Clear适用于 C6,D6项目<br />
Crystal Yellow适用于 C20,D20,E20项目<br />
Crystal Orange 适用于 C40,D40,E40项目<br />
Crystal Red 适用于 C80,D80,E80项目</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">Crystal Clear</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">适用于一个办公室内的一个小组</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">角色有： sponsor发起人，任务下达者<br />
Senior Designer-Programmer 高级设计开发人员<br />
Designer-Programmer 设计开发人员<br />
User 用户<br />
其中一个人是项目协调者(Project Coordinator)。Senior Designer-Programmer是关键人员</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">策略：<br />
1 软件的开发采用有规则的周期性递增方法，每2-3个月提交（deliver）一个版本<br />
2 使用里程碑(milestone)跟踪进度（包括delvier和开发期间的重大决定）<br />
3 自动<a href="http://www.itisedu.com/phrase/200603120943595.html" target="_new">回归测试</a>
（automated regression test）<br />
4 用户直接参与<br />
5 每个release有两个user viewings(用户审核?)<br />
6 在上一个步骤足够稳定（stable enough to review）时立即开始下一个步骤，尽量并行开发<br />
7 在每个周期的开始和中间进行产品和过程调整</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">过程产品（指整个过程产生的所有产品，包括软件和文档）<br />
1 软件释放顺序（release sequence）<br />
2 用户审核的计划<br />
3 用户案例（usecase）或需求描述<br />
4 设计<a href="http://www.itisedu.com/phrase/200603061723295.html" target="_new">框架</a>
和必要的说明<br />
5 界面草图<br />
6 基本的<a href="http://www.itisedu.com/phrase/200603090845215.html" target="_new">对象</a>
模型<br />
7 执行代码<br />
8 migration code<br />
9 <a href="http://www.itisedu.com/phrase/200603291707535.html" target="_new">测试用例</a>
<br />
10 用户手册<br />
11 local matters有项目组决定：<br />
上述product的摸班<br />
编码和用户界面的标准<br />
回归测试的标准和细节<br />
其他文档<br />
需要的工具：<br />
<a href="http://www.itisedu.com/phrase/200603292355295.html" target="_new">版本控制</a>
工具<br />
白板（最好可打印）</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
Crystal Orange</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">角色：sponsor 发起人<br />
business export/usage export 业务专家<br />
technical facilitator 技术专家<br />
business analyst/designer 业务分析和设计人员<br />
project manager <a href="http://www.itisedu.com/phrase/200604240825565.html" target="_new">项目管理</a>
员<br />
architect 系统架构人员<br />
Design Mentor 设计指导人员<br />
Lead Designer-Programmer 主要设计编码人员、<br />
Other Designer-Programmer设计编码人员<br />
UI Designer 用户界面设计人员<br />
Writer 文档写作人员<br />
Tester 测试人员</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">策略：<br />
同Crystal Clear (周期可以为3-4个月)<br />
过程产品：<br />
需求文档<br />
计划<br />
状态报告<br />
用户界面设计文档<br />
基本对象模型<br />
外部接口标准<br />
用户手册<br />
源代码<br />
测试<a href="http://www.itisedu.com/phrase/200604240937105.html" target="_new">用例</a>
<br />
migration code<br />
local matters 同Crystal Clear</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
（四） The Agile Alliance</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">敏捷联盟是17位不同敏捷开发方法的提倡者共同成立的，目的是推进敏捷开发方法的研究和应用，他们并不要求强制使用某种开发方法，而是提出了敏捷开发的几个核心价值和基本原则：<br />
core value:</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">Individuals and interactions over processes and tools <br />
个人和交流重于过程和工具<br />
Working software over comprehensive documentation <br />
正在运行的软件本身重于复杂的文档<br />
Customer collaboration over contract negotiation <br />
与客户的沟通和交流重于使用合同约束客户<br />
Responding to change over following a plan<br />
对变化的快速响应重于跟随计划</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">principles</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">1 最高目标是通过快速的和经常的发布软件满足客户的需要<br />
2 提交软件的周期为几个星期到几个月<br />
3 产生正确的软件是衡量进度的首要标准<br />
4 主动接受需求的改变而不是拒绝<br />
5 商务人员和开发人员工作在一起<br />
6 个人必须有动力，要创造环境支持他们的要求，信任他们<br />
7 最有效的交流方法是面对面的交流<br />
8 最好的结构，需求和设计来自于自组织的团队（self-organizing team），允许任何人提出想法和建议<br />
9 持续改进设计和编码<br />
10 鼓励正常工作，减少长时间加班<br />
11 保持简单，减少不必要的部分，认识到简单的设计比复杂的设计更难（simple design is harder to produce）<br />
12 定期调整过程，获得更高效率</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
（五） Extreme <a href="http://www.itisedu.com/phrase/200604232129205.html" target="_new">Programming</a>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">Extreme Programming（XP，<a href="http://www.itisedu.com/phrase/200603071747045.html" target="_new">极限编程</a>
）
是一种轻量级的软件开发方法，它使用快速的反馈，大量而迅速的交流，经过保证的测试来最大限度的满足用户的需求。XP强调用户满意，开发人员可以对需求的
变化作出快速的反应。XP强调team
work。项目管理者，用户，开发人员都处于同一个项目中，他们之间的关系不是对立的，而是互相协作的，具有共同的目标：提交正确的软件。XP强调4个因
素：<br />
交流(communication)，XP要求程序员之间以及和用户之间有大量而迅速的交流<br />
简单（simplicity），XP要求设计和实现简单和干净<br />
反馈（feedback）通过测试得到反馈，尽快提交软件并根据反馈修改<br />
勇气（courage）。勇敢的面对需求和技术上的变化</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">XP特别适用于需求经常改变的领域，客户可能并系统的功能并没有清晰的认识，可能系统的需求经常需要变动。<br />
XP也适用于风险比较高的项目，当开发人员面对一个新的领域或技术时，XP可以帮助减低风险<br />
XP适用于小的项目（人员上），人员在2-12人之间，XP不适用于人员太多的项目，事实上，在需求经常变化或风险比较高的项目中，少量而有效的XP开发人员效率要远远高于大量的开发人员。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">下面是XP的开发流程</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
XP的原则和实践：</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">1 Planning:</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">1)user stories。<br />
User stories类似<a href="http://www.itisedu.com/phrase/200603042249305.html" target="_new">use case</a>
，
描述用户所见的系统功能，但避免使用大量的文档，user stories由用户编写（不仅限于描述用户界面）。User
stories使用用户的语言编写，不使用技术性的语言，每个user stories限于几句话。User stories用于在release
plan会议上对开发时间进行评估，也用于产生<a href="http://www.itisedu.com/phrase/200603282249515.html" target="_new">验收测试</a>
（acceptance
test），必须使用可以自动进行的验收测试保证软件的正确性。User stories与传统的用户需求的区别在于详细的程度，user
stories并不会确定需求的每个细节，它只是用来简单的描述系统功能，供开发人员进行估计开发进度，在开发过程中开发人员和用户会不断的交流以讨论细
节问题。User story应该专注于功能，不应该过分注重用户界面等细节。一般一个user
storiy在1-3周的时间完成，如果估计超过3周，说明user story太大了，需要细分。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">2)release plan.<br />
召开一个
release plan会议，产生release plan。Release
plan将用于指定每个iteration的计划。开发人员对每个user
story估计开发时间（在不被打断，无其他工作情况下的开发时间，包括测试），用户对user stories给出优先级，release
plan会议并不制订每个iteration的计划。Release
plan要用户，开发人员和管理者都同意，在完成功能范围（scope），使用资源（resource）,时间（time）和质量(quality)上达
成一致（一般质量是不能改变的）</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">3) small release<br />
often and small release是XP的一个原则，每个release完成一些用户有意义的功能集合，尽快的提交给用户以获得反馈，及时调整，提交的越晚，调整越困难。<br />
4）project velocity<br />
团队在开发过程中要收集数据，以便于对自己的开发速度进行评估，用于以后的releazse plan</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">5)iteration<br />
每个small
release的周期称为iteration，每个iteration约为1-3周，在一个项目中保持每个iteration的时间相等，不要超前制定计
划，每个iteration的计划在iteration的开始时制定。这样能够更灵活的应付变化。不要急于完成本次iteration没有包括的功能。要
注重每个iteration的时间限制，当团队觉得不能按时完成iteration时，召开一次iteration
plan会议，重新评估，减少一些user stories。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">下面是iteration的图示：</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">6）iteration plan<br />
在每个
iteration开始的时候召开会议，从release plan中选择还没有实现的用户最迫切需要的user
stories。上一个iteration中没有通过验收测试的功能也要在这个iteration中实现。可以根据上一个iteration的实践调整团
队速度。User stories和失败的测试被分解成programming task，task使用技术语言编写，作为iteration
plan的详细描述。程序员主动领取task并估计完成时间，每个task应该在1-3天内完成，超过3天的task应该被细分。如果整个团队需要的时间
多于或少于规定的iteration时间，调整user stories。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">7）move people around<br />
不要使每个开发人员局限于一项工作，不要使某项工作依赖于一个开发人员，增加知识共享，减少信息孤岛，多进行交流和培训。当项目中的所有人对所有模块都了解并可以进行开发时是效率最高的，鼓励开发人员在不同iteration中开发不同的模块。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">8) stand-up meeting<br />
每天工作
开始之前，开5-10分钟的stand-up会议（站立会议），站立的目的是为了强迫节省时间，会议的目的是交流，提出存在的问题，但不要在会议上解决问
题。开一个所有人员参加的短会比多个个别人员参加的会议要高效。在会议上提出的问题可以由少数人讨论解决，这个少数人参加的会议如果涉及到代码，可以在<a href="http://www.itisedu.com/phrase/200603021438435.html" target="_new">计算机</a>
前讨论。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">9) fix XP when it breaks<br />
XP并不是一成不变的，当团队觉得需要修改的时候，可以根据自己的情况进行修改，任何修改都要经过整个团队的讨论和达成一致</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">2 Designing</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">1) Simplicity<br />
保持简单的设计，在完成同样的功能的情况下，选择简单的设计，不要急于设计没有计划的功能，应该认识到：keeping a design simple is hard work</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">2）system metaphor<br />
使用统一的术语描述系统，在用户，管理者和开发人员之间使用统一的术语。这将使交流清晰。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">3）CRC card<br />
使用CRC(<a href="http://www.itisedu.com/phrase/200604231359565.html" target="_new">Class</a>
,
Responsibilities, and Collaboration)
card进行系统设计，鼓励更多的人参加设计。每个CRC卡片表示系统中一个对象，写上对象的名字，责任和每个责任需要交互的其他对象。可以模拟对象之间
的交互。CRC卡片是易于理解的，但是是非正式的，如果需要正式的文档，要将卡片转换为相应的文档。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">4) spike solution<br />
使用spike solution减低风险，当遇到技术难题或设计问题时，使用简单的程序进行测试，找出问题，在不同的解决方法之间进行评估。在早期进行实验可以有效的降低风险。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">5）never add function early<br />
不要过早的设计没有计划的功能，在一个需求经常变化的环境中，过早的设计经常是没有用的。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">6）refactoringwhenever and wherever<br />
XP鼓励对设计和代码经常进行<a href="http://www.itisedu.com/phrase/200603121222205.html" target="_new">重构</a>
（<a href="http://www.itisedu.com/phrase/200604232047545.html" target="_new">Refactoring</a>
），目的是去除冗余，提高质量，保持设计简单。重构必须以完全测试为检验条件</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
3 Coding</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">1) customer is alaways available<br />
用户是项目组的成员之一，用户的参加贯穿整个开发过程，用户与开发人员之间的交流是重要的</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">2) coding standard<br />
使用统一的编码标准，这是保持代码整洁和共享代码的基础</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">3）coding unit test first<br />
test first是XP的一个特点，在编写代码之前先编写<a href="http://www.itisedu.com/phrase/200602281036115.html" target="_new">单元测试</a>
代码，单元测试代码和代码由同一个程序员完成。先编写测试代码可以使程序员更好的理解需求，避免直接编码造成的理解偏差，对需求的不清晰，可以在编写测试代码时就发现。测试代码也是检验程序是否完成的标准。编码工作应该是以下工作的循环：<br />
1 编写测试代码<br />
2 运行测试程序，确认失败<br />
3 编写实现这个测试程序要求功能的代码，不需要实现其他的功能，只需要实现刚刚满足测试程序的功能<br />
4 运行测试程序，确认成功<br />
实践证明，test first方式需要的编码实践少于先编码，后写测试代码</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">4) Pair Programming<br />
Pair
programming是XP的特色，它要求两个程序员在一台计算机上同时进行编程工作。共用鼠标和键盘，通常一个人进行战略上的思考，程序架构和函数，
类之间的关系，一个人进行输入和战术上的思考，完成函数和类。两个人可以经常交换角色。Pair
programming需要一段时间学习和适应，实践证明pair
programming并不消耗更多的时间(人*小时)，但是代码的质量得到很大的提高。（避免将两个新手放在一个pair中）</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">5）sequential integration<br />
要保证源代码库的状态是可标识的，同一时间，只允许一个pair的程序进行整和和测试，这样可以缩小问题产生的范围。不同的pair可以在自己的机器上随时进行整和和测试.</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">6) integrate often<br />
只要有可能
就进行代码整合，周期可以在几个小时，最好不要超过一天。经常的整合可以避免错误的积累，可以增加可重用的代码。在一个pair认为适当的时候并通过了所
有的unit
test，就可以进行整合，整合后的代码必须通过测试。同一时间，只允许一个pair进行整合。(整合失败是不是要退回原有状态，供其他pair整
合？？)</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">7) 共同拥有代码<br />
鼓励每个人对项目中的任何人提
出新的想法，任何开发人员对项目中的任何代码都可以进行增加功能，改正错误和重构。没有代码或开发人员成为瓶颈。（我的想法：这确实很难理解，但是这确实
是我梦想的目标）。为了达到这个目标，任何的代码都必须有相应的测试代码，任何代码的修改必须100%通过测试。必须加强开发人员的交流和知识共享，必须
坚持统一编码标准。Pair programming可以经常交换伙伴。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">8）优化工作放在最后<br />
先使系统能够正常工作，不要猜测系统的瓶颈，要实际测量</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">9）NO overtime<br />
不要长时间的加班，大多数加班并不能挽回已有的延迟，连续超过两个星期的加班说明有问题存在。向一个已经延迟的项目填加人员也不是一个好的选择。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
4Testing</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">1)所有的代码都有单元测试<br />
单元测试是XP的基
石，XP中的单元测试应该是可以自动进行的，所以可以很快的进行所有的单元测试，单元测试应该在编码之前创建。单元测试的代码和代码一起release，
没有单元测试的代码不能够release。使用自动单元测试可以系统整合时节省大量的发现错误和改正的时间。单元测试越完善，节省的时间越多。对<a href="http://www.itisedu.com/phrase/200603101726185.html" target="_new">面向对象</a>
的编程来说，应该对每个类都有单元测试。完善的单元测试也是共同拥有代码的保证。单元测试也是可以经常重构的保证，每次重构后的代码都要重新进行测试<br />
（这里的unit test好象不只限于测试某个模块的功能？？？，应该可以测试整合起来的整个系统，这样才能保证整合的正确性。）</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">2）代码在release前必须通过所有的单元测试</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">3) 发现bug后，首先增加测试<br />
在实际运行中发现bug,首先增加acceptance test，然后增加unit test，在增加完测试后在查找和修改代码，增加的测试保证同样的错误不会再出现</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">4) acceptance test<br />
acceptance test根据user stories在iteration plan会议上创建，它也应该可以自动运行以便可以经常运行。User stories是否完成是以是否通过acceptance test为检验标准。</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
XP中的角色：</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">1 customer 用户<br />
在XP中，用户是项目组的一部分，用户负责编写use stories，确定优先级，和开发人员讨论需求，编写accept test，运行accept test，用户驱动iteration(release plan, iteration plan)</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">2 开发人员<br />
与用户讨论user stories，估计开发时间，将user stories细化成programming task<br />
编写unit test<br />
编码<br />
进行重构<br />
整合及测试，保证100通过</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">3 manager<br />
负责对外联系，组织团队，获取必要的资源，管理团队</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">4 tracker<br />
跟踪release plan/iteration plan/acceptance test</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">5 coach<br />
起顾问指导作用，mentor, monitor and help<br />
A
Coach is respected, but also respectful. They&rsquo;re willing to talk, but
also willing to listen. They let the team explore, but provide a
guard-rail in case of danger.<br />
监督进展，确保过程和规则，必要时改变过程，帮助解决问题，也可以参加pair programming。<br />
</span>
</span>
</p>
<span style="font-family: Verdana;"><span style="font-family: Verdana;">
</span>
</span>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;"><strong>二、敏捷开发的设计原则</strong>
</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">关于敏捷开发的设计原则：<br />
单一职责原则SRP：Single Responsibility Principle<br />
开放封闭原则OCP：Open－Close Principle<br />
Liskov替换原则LSP：Liskov Substitution Principle<br />
依赖倒置原则DIP：Dependency Invertion Principle<br />
接口隔离原则ISP：Interface Separate Principle<br />
关于包的设计原则：<br />
重用发布等价原则REP：Reuse Equivalence Principle<br />
共同重用原则CRP：Common Resue Principle<br />
共同封闭原则CCP：Common Close Principle<br />
无环依赖原则ADP：Acyclic Dependency Principle<br />
稳定依赖原则SDP：Stabilization Dependency Principle<br />
稳定性度量公式：I＝Ce/(Ca+Ce) (I:不稳定度，Ce:输入耦合度，Ca：输出耦合度)<br />
I取值范围在【0，1】，I＝0表示具有最大稳定度；iI＝1标识具有最大不稳定度<br />
稳定抽象原则<a href="http://www.itisedu.com/phrase/200604080959005.html" target="_new">SAP</a>
：Stabilization Abstract Principle</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;">&nbsp;</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;"><a href="http://www.itisedu.com/phrase/200603061811045.html" target="_new">GOF</a>
说－－基于对象组合的设计会有更多的对象（而有较少的类）。<br />
如果单纯的看这里，你会明白似乎类较少符合面向对象的逻辑。<br />
但是且慢，我们知道面向对象有一条原则叫单一职责原则－－SRP。<br />
这样好像类多又是面向对象思想的体现。<br />
其实最重要的是GOF中的这句话－－且系统的行为将依赖对象间的关系而不是被定义在某个类中。<br />
所以类的多少并不是问题的关键，是否职责单一也不是大问题，<br />
最重要的是你现在的那些职责是都多少是不能被别的职责通过某种方式所代替的。<br />
在BOB大叔那里定义职责是变化的原因，因此就可以认为这些变化的原因应该是不可代替的，<br />
也可以说你不能由这个原因推导出别的原因。<br />
只要这个原因间可以做到相互关联，那么你就可以把由于这些变化而引起变化的类组合起来，<br />
而不是把他们规定在新的类中。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">开放封闭原则OCP：Open－Close Principle</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">因此在进行<a href="http://www.itisedu.com/phrase/200603050045535.html" target="_new">面向对象设计</a>
时要尽量考虑接口封装机制、抽象机制和多态技术。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">该原则同样适合于非面向对象设计的方法，是软件工程设计方法的重要原则之一。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">我们以收音机的例子为例，讲述面向对象的开闭原则。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">我们收听节目时需要打开收音机电源，对准电台频率和进行音量调节。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">但是对于不同的收音机，实现这三个步骤的细节往往有所不同。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">比如自动收缩电台的收音机和按钮式收缩在操作细节上并不相同。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">因此，我们不太可能针对每种不同<a href="http://www.itisedu.com/phrase/200603051002565.html" target="_new">类型</a>
的收音机通过一个收音机类来实现（通过重载）这些不同的操作方式。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">但是我们可以定义一个收音机接口，提供开机、关机、增加频率、降低频率、增加音量、降低音量六个抽象方法。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">不同的收音机继承并实现这六个抽象方法。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">这样新增收音机类型不会影响其它原有的收音机类型，收音机类型扩展极为方便。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">此外，已存在的收音机类型在修改其操作方法时也不会影响到其它类型的收音机。 <br />
图1是一个应用OCP生成的收音机<a href="http://www.itisedu.com/phrase/200603071659325.html" target="_new">类图</a>
的例子：</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">Liskov替换原则LSP：Liskov Substitution Principle</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">子类应当可以替换父类并出现在父类能够出现的任何地方。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">我们以学生为例，夜校生为学生的子类，因此在任何学生可以出现的地方，夜校生均可出现。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">这个例子有些牵强，</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">一个能够反映这个原则的例子时圆和椭圆，圆是椭圆的一个特殊子类。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">因此任何出现椭圆的地方，圆均可以出现。但反过来就可能行不通。 </span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　运用替换原则时，我们尽量把类B设计为抽象类或者接口，</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">让C类继承类B（接口B）并实现操作A和操作B，</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">运行时，类C实例替换B，这样我们即可进行新类的扩展（继承类B或接口B），</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">同时无须对类A进行修改。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">依赖倒置原则DIP：Dependency Invertion Principle</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">在进行业务设计时，与特定业务有关的依赖关系应该尽量依赖接口和抽象类，而不是依赖于具体类。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">具体类只负责相关业务的实现，修改具体类不影响与特定业务有关的依赖关系。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">在结构化设计中，我们可以看到底层的模块是对高层抽象模块的实现（高层抽象模块通过调用底层模块），</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">这说明，抽象的模块要依赖具体实现相关的模块，</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">底层模块的具体实现发生变动时将会严重影响高层抽象的模块，显然这是<a href="http://www.itisedu.com/phrase/200602281749185.html" target="_new">结构化方法</a>
的一个&quot;硬伤&quot;。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
　　<a href="http://www.itisedu.com/phrase/200602281513385.html" target="_new">面向对象方法</a>
的依赖关系刚好相反，具体实现类依赖于抽象类和接口</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　为此，我们在进行业务设计时，应尽量在接口或抽象类中定义业务方法的原型，</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">并通过具体的实现类（子类）来实现该业务方法，业务方法内容的修改将不会影响到运行时业务方法的调用</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">接口隔离原则ISP：Interface Separate Principle</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">采用多个与特定客户类有关的接口比采用一个通用的涵盖多个业务方法的接口要好。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;"><br />
　　ISP原则是另外一个支持诸如COM等<a href="http://www.itisedu.com/phrase/200603302222545.html" target="_new">组件</a>
化的使能技术。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">缺少ISP，组件、类的可用性和移植性将大打折扣。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">这个原则的本质相当简单。如果你拥有一个针对多个客户的类，</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">为每一个客户创建特定业务接口，然后使该客户类继承多个特定业务接口将比直接加载客户所需所有方法有效。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">以下展示了一个拥有多个客户的类。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">它通过一个巨大的接口来服务所有的客户。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">只要针对客户A的方法发生改变，客户B和客户C就会受到影响。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">因此可能需要进行重新编译和发布。这是一种不幸的做法。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">所展示的技术。每个特定客户所需的方法被置于特定的接口中，这些接口被Service类所继承并实现。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">如果针对客户A的方法发生改变，客户B和客户C并不会受到任何影响，也不需要进行再次编译和重新发布。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;"><strong>三、</strong>
</span>
<span style="font-family: Verdana;"><strong>敏捷开发技术在<a href="http://www.itisedu.com/phrase/200603011335015.html" target="_new">电子商务</a>
软件中的应用</strong>
 <br />
&nbsp;<br />
　　第一章 背景介绍</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　1.1 电子商务背景</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　随着企业
信息化的不断进步，电子商务在中国也越来越得到更多的认可，电子商务的应用也越来越多，但是很多企业对电子商务的概念和应用还不是很清楚，行业内对电子商
务的研究模式和实施方法也存在很多问题。因此很多企业在实施电子商务系统的过程中都处在探索和摸索当中，对于项目开发方来说也有着极大的风险性和挑战性。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　1.2 电子商务软件开发存在的问题</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　由于电子
商务软件开发存在很大的风险性，而且电子商务的应用也出在不断摸索当中，没有很多成熟的模式可以参考，所以没有实践的指导可能会导致的项目噩梦。缺乏有效
的实践会导致不可预测性、重复的错误以及努力的白白浪费。延期的进度、增加的预算和低劣的质量致使客户对我们丧失信心。更长时间的工作却生产出更加低劣的
软件产品，也使得开发人员感到沮丧。我们希望这些方法这次还会有效，从而消除我们的恐惧。然而，项目并没有简单到使用一些约束和人为制品就能够可靠地防止
错误的地步。当连续地犯错误时，我们会对错误进行诊断，并在过程中增加更多的约束和人为制品来防止以后重犯这样的错误。一个大而笨重的过程会产生它本来企
图去解决的问题。它降低了团队的开发效率，使得进度延期，预算超支。它降低了团队的响应能力，使得团队经常创建错误的产品。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　1.3 敏捷开发技术概述</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　敏捷式开发采用适应性方法，而传统的软件工程学采用的是预测性方法。敏捷式开发是以人为主的，而传统的工程学是以过程为主的。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　1.4 敏捷开发的现实意义</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　适应性和
预测性的区别存在于软件工程学对软件开发过程的描述中。在传统的工程学里，核心的概念就是把设计和构建这两个过程分开进行。在软件开发的过程中，我们很难
想象，如何真正把设计和编程完全区分过来。软件工程学领域，所有在这里从事工作的人员，都把设计的过程想象成用图表、图象的方式来描述结果的过程。还有一
个更重要的问题就是说，软件本身的需求是在变化的。一个项目在开发过程中需求会出现变化，需求的变化从根本上推翻了工程学方法所建立的一个基础。当工程学
的人尽量减少或者控制系统将来发生变化的可能，他越这样做问题就越容易出现。既然我们没办法避免变化的发生，那么我们就想找到一种新的方法能够更有效地适
应这种变化现象。这也就是敏捷式开发方法所要达到的效果。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　第二章 敏捷开发技术的应用</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　2.1 敏捷开发技术的几种主要类型</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">1.XP（Extreme Programming －－ 极限编程</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">2.Cockburn的水晶系列方法</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">3.开放式源码</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">4.Highsmith的适应性软件开发方法〔ASD〕</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　　2.2 敏捷开发技术的特点和优势</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　1．个体和交互胜过过程和工具</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"><span style="font-family: Verdana;"><span style="font-family: Verdana;">　　人是获得
成功的最为重要的因素。如果团队中没有优秀的成员，那么就是使用好的过程也不能从失败中挽救项目，但是，不好的过程却可以使最优秀的团队成员失去效用。如
果不能作为一个团队进行工作，那么即使拥有一批优秀的成员也一样会惨败。团队的构建要比环境的构建重要得多。许多团队和管理者就犯了先构建环境，然后期望
团队自动凝聚在一起的错误。相反，应该首先致力于构建团队，然后再让团队基于需要来配置环境。</span>
</span>
</span>
</p>
<p><span style="font-family: Verdana;"></span>
</p>
</div>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/229880#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 17:39:46 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/229880</link>
        <guid>http://hex.javaeye.com/blog/229880</guid>
      </item>
      <item>
        <title>Java正则表达式</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/226304" style="color:red;">http://hex.javaeye.com/blog/226304</a>&nbsp;
          发表时间: 2008年08月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <ol>
<li>两个问题</li>
</ol>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong> a. 如何知道一个url是新浪论坛的帖子页</strong>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>b. 如何提取这些页面的发帖时间</strong>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 分析：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 新浪论坛的帖子页url实例：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://bbs.2008.sina.com.cn/tableforum/App/view.php?bbsid=274&amp;subid=0&amp;fid=32614&amp;tbid=2351">http://bbs.2008.sina.com.cn/tableforum/App/view.php?bbsid=274&amp;subid=0&amp;fid=32614&amp;tbid=2351</a>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://bbs.book.sina.com.cn/tableforum/App/view.php?bbsid=7&amp;subid=1&amp;fid=43640&amp;tbid=5386">http://bbs.book.sina.com.cn/tableforum/App/view.php?bbsid=7&amp;subid=1&amp;fid=43640&amp;tbid=5386</a>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://bbs.book.sina.com.cn/tableforum/App/view.php?bbsid=192&amp;subid=4&amp;fid=10367&amp;tbid=1683">http://bbs.book.sina.com.cn/tableforum/App/view.php?bbsid=192&amp;subid=4&amp;fid=10367&amp;tbid=1683</a>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://bbs.edu.sina.com.cn/tableforum/App/view.php?bbsid=41&amp;subid=2&amp;fid=86455&amp;tbid=4803">http://bbs.edu.sina.com.cn/tableforum/App/view.php?bbsid=41&amp;subid=2&amp;fid=86455&amp;tbid=4803</a>
</p>
<p>&nbsp;</p>
<p>&nbsp; 发现很有规律。规则差不多是这样：</p>
<p><a href="http://bbs.[a-zA-Z0-9]+.sina.com.cn/tableforum/App/view.php?bbsid=[0-9]+&amp;subid=[0-9]+&amp;fid=[0-9]+&amp;tbid=[0-9">http://bbs\.[a-zA-Z0-9]+\.sina\.com\.cn/tableforum/App/view.php\?bbsid=[0-9]+&amp;subid=[0-9]+&amp;fid=[0-9]+&amp;tbid=[0-9</a>
]+&nbsp;&nbsp;&nbsp;&nbsp; (.与?需要转义,写成\.与\?)</p>
<p>&nbsp;</p>
<p>发帖时间都这样的：[2008-08-09 14:51:35]&nbsp;</p>
<p>&nbsp;&nbsp; 规则：\[&nbsp;(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)\]</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>
<table rules="groups" cellspacing="0" border="0" frame="hsides" cellpadding="5">
<caption>
<h5 class="docTableTitle">&nbsp;Regular Expression Syntax</h5>
</caption>
<colgroup span="1"><col span="1" width="181" />
<col span="1" width="368" />
</colgroup>
<thead>
<tr>
<th scope="col" class="bottomBorder thead" align="left" valign="middle">
<p class="docText"><span class="docEmphStrong">Syntax</span>
</p>
</th>
<th scope="col" class="bottomBorder thead" align="left" valign="middle">
<p class="docText"><span class="docEmphStrong">Explanation</span>
</p>
</th>

</tr>
</thead>

<tbody>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Characters</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>c</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">The character <span class="docEmphasis">c</span>
<a name="ch12index238"></a>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\</tt>
u<span class="docEmphasis">nnnn</span>
, <tt>\</tt>
x<span class="docEmphasis">nn,</span>
 <tt>\</tt>
0<span class="docEmphasis">n</span>
, <tt>\</tt>
0<span class="docEmphasis">nn</span>
, <tt>\</tt>
0<span class="docEmphasis">nnn</span>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">The code unit with the given hex or octal value</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\</tt>
t, <tt>\</tt>
n, <tt>\</tt>
r, <tt>\</tt>
f, <tt>\</tt>
a, \e</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">The control characters tab, newline, return, form feed, alert, and escape</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\</tt>
c<span class="docEmphasis">c</span>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">The control character corresponding to the character <span class="docEmphasis">c</span>
</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Character Classes</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>[</tt>
<span class="docEmphasis">C</span>
<sub>1</sub>
<span class="docEmphasis">C</span>
<sub>2</sub>
. . .<tt>]</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Any of the characters represented by <span class="docEmphasis">C</span>
<sub>1</sub>
, <span class="docEmphasis">C</span>
<sub>2</sub>
, . . . The <span class="docEmphasis">C<sub>i</sub>
</span>
 are characters, character ranges (<span class="docEmphasis">c</span>
<sub>1</sub>
-<span class="docEmphasis">c</span>
<sub>2</sub>
), or character classes</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>[^</tt>
. . .<tt>]</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Complement of character class</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>[</tt>
 . . . <tt>&amp;&amp;</tt>
 . . .<tt>]</tt>
 </p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Intersection of two character classes</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Predefined Character Classes</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>.</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Any character except line terminators (or any character if the <tt>DOTALL</tt>
 flag is set)</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\d</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A digit [<tt>0-9</tt>
]</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\D</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A nondigit [^<tt>0-9</tt>
]</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\s</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A whitespace character [ <tt>\t\n\r\f\x0B</tt>
]</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\S</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A non-whitespace character</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\w</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A word character [<tt>a-zA-Z0-9</tt>
_]</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\W</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A nonword character</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\p{</tt>
<span class="docEmphasis"><tt>name</tt>
</span>
<tt>}</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A named character class&mdash;see <a href="../#ch12table56" class="docLink">Table 12-9</a>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\P{</tt>
<span class="docEmphasis"><tt>name</tt>
</span>
<tt>}</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">The complement of a named character class</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Boundary Matchers</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>^ $</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Beginning, end of input (or beginning, end of line in multiline mode)</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\b</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">A word boundary</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top">
<p class="docText"><tt>\B</tt>
</p>
</td>
<td class="bottomBorder" align="left" valign="top">
<p class="docText">A nonword boundary</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="middle">
<p class="docText"><span class="docEmphStrong">Syntax</span>
</p>
</td>
<td class="bottomBorder" align="left" valign="middle">
<p class="docText"><span class="docEmphStrong">Explanation</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\A</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Beginning of input</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\z</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">End of input</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\Z</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">End of input except final line terminator</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\G</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">End of previous match</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Quantifiers</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText">X?</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Optional X</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText">X*</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">X, 0 or more times</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><span class="docEmphasis">X</span>
+</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">X, 1 or more times</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><span class="docEmphasis">X</span>
{<span class="docEmphasis">n</span>
} <span class="docEmphasis">X</span>
{<span class="docEmphasis">n</span>
,} <span class="docEmphasis">X</span>
{<span class="docEmphasis">n,m</span>
}</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">X <span class="docEmphasis">n</span>
 times, at least <span class="docEmphasis">n</span>
 times, between <span class="docEmphasis">n</span>
 and <span class="docEmphasis">m</span>
 times</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Quantifier Suffixes</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>?</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Turn default (greedy) match into reluctant match</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>+</tt>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Turn default (greedy) match into possessive match</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Set Operations</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText">XY</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Any string from <span class="docEmphasis">X</span>
, followed by any string from <span class="docEmphasis">Y</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText">X|Y</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Any string from <span class="docEmphasis">X</span>
 or <span class="docEmphasis">Y</span>
</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Grouping</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText">(X)</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Capture the string matching <span class="docEmphasis">X</span>
 as a group</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\</tt>
<span class="docEmphasis"><tt>n</tt>
</span>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">The match of the <span class="docEmphasis">n</span>
th group</p>
</td>
</tr>
<tr>
<td class="bottomBorder" align="left" valign="top" colspan="2">
<p class="docText"><span class="docEmphStrong">Escapes</span>
</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\</tt>
<span class="docEmphasis"><tt>c</tt>
</span>
</p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">The character <span class="docEmphasis">c</span>
 (must not be an alphabetic character)</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>\</tt>
<span class="docEmphasis"><tt>Q</tt>
</span>
 . . . <tt>\E</tt>
 </p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Quote . . . verbatim</p>
</td>
</tr>
<tr>
<td class="docTableCell" align="left" valign="top">
<p class="docText"><tt>(?</tt>
 . . . <tt>)</tt>
 </p>
</td>
<td class="docTableCell" align="left" valign="top">
<p class="docText">Special construct&mdash;see API notes of Pattern class</p>
</td>
</tr>
</tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>从html中去除标签，提取正文的正则表达式：</p>
<p><span style="color: #008000;">&lt;script.*?&lt;/script&gt;|&lt;style.*?&lt;/style&gt;|&lt;!?[a-z]+[^&gt;]*&gt;|&lt;/[a-z0-9]+&gt;|&lt;!--.*?--&gt;</span>
</p>
<p>&nbsp;</p>
<p>上传一个正则表达式测试工具：</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://hex.javaeye.com/blog/226304#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 10 Aug 2008 13:21:34 +0800</pubDate>
        <link>http://hex.javaeye.com/blog/226304</link>
        <guid>http://hex.javaeye.com/blog/226304</guid>
      </item>
      <item>
        <title>Java theory and practice: Dealing with Interrupte</title>
        <author>sole</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://hex.javaeye.com">sole</a>&nbsp;
          链接：<a href="http://hex.javaeye.com/blog/221107" style="color:red;">http://hex.javaeye.com/blog/221107</a>&nbsp;
          发表时间: 2008年07月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <blockquote>Many Java&trade; language methods, such as <code>Thread.sleep()</code> and <code>Object.wait()</code>, throw <code>InterruptedException</code>. You can't ignore it because it's a checked exception, but what should you do with it? In this month's <em>Java theory and practice</em>, concurrency expert Brian Goetz explains what InterruptedException means, why it is thrown, and what you should do when you catch one. </blockquote>
<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
<p>
<script type="text/javascript"></script>
</p>
<!--  START : HTML FOR SEARCH REFERRER -->
<div id="search_referrer_results" style="display: none;"><!-- START KRUGLE SEARCH HEADING PLAY
					
<table width="580" cellspacing="0" cellpadding="0" border="0">
<tr>
<td class="v14-header-5">
                     <strong>Show more developerWorks content related to my search</strong>
                      </td>
</tr>
</table>
--><!--  START : HTML FOR ARTICLE SEARCH --><!--  END : HTML FOR ARTICLE SEARCH --><!--  START : HTML FOR CODE SEARCH --><!--  END : HTML FOR CODE SEARCH --><br /><br /></div>
<!--  END : HTML FOR SEARCH REFERRER --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
<p>This story is probably familiar: You're writing a test program and you need to pause for some amount of time, so you call <code>Thread.sleep()</code>. But then the compiler or IDE balks that you haven't dealt with the checked <code>InterruptedException</code>. What is <code>InterruptedException</code>, and why do you have to deal with it? </p>
<p>The most common response to <code>InterruptedException</code> is to swallow it -- catch it and do nothing (or perhaps log it, which isn't any better) -- as we'll see later in <a href="../#code4"><span style="color: #5c81a7;">Listing 4</span></a>. Unfortunately, this approach throws away important information about the fact that an interrupt occurred, which could compromise the application's ability to cancel activities or shut down in a timely manner. </p>
<p><a name="1.0"><span class="atitle">Blocking methods</span></a></p>
<p>When a method throws <code>InterruptedException</code>, it is telling you several things in addition to the fact that it can throw a particular checked exception. It is telling you that it is a <em>blocking</em> method and that it will make an attempt to unblock and return early -- if you ask nicely. </p>
<p>A blocking method is different from an ordinary method that just takes a long time to run. The completion of an ordinary method is dependent only on how much work you've asked it to do and whether adequate computing resources (CPU cycles and memory) are available. The completion of a blocking method, on the other hand, is also dependent on some external event, such as timer expiration, I/O completion, or the action of another thread (releasing a lock, setting a flag, or placing a task on a work queue). Ordinary methods complete as soon as their work can be done, but blocking methods are less predictable because they depend on external events. Blocking methods can compromise responsiveness because it can be hard to predict when they will complete. </p>
<p>Because blocking methods can potentially take forever if the event they are waiting for never occurs, it is often useful for blocking operations to be <em>cancelable</em>. (It is often useful for long-running non-blocking methods to be cancelable as well.) A cancelable operation is one that can be externally moved to completion in advance of when it would ordinarily complete on its own. The interruption mechanism provided by <code>Thread</code> and supported by <code>Thread.sleep()</code> and <code>Object.wait()</code> is a cancellation mechanism; it allows one thread to request that another thread stop what it is doing early. When a method throws <code>InterruptedException</code>, it is telling you that if the thread executing the method is interrupted, it will make an attempt to stop what it is doing and return early and indicate its early return by throwing <code>InterruptedException</code>. Well-behaved blocking library methods should be responsive to interruption and throw <code>InterruptedException</code> so they can be used within cancelable activities without compromising responsiveness. </p>
<p><a name="1.1"><span class="smalltitle"><strong><span style="font-size: small; font-family: Arial;">Thread interruption</span></strong></span></a></p>
<p>Every thread has a Boolean property associated with it that represents its <em>interrupted status</em>. The interrupted status is initially false; when a thread is interrupted by some other thread through a call to <code>Thread.interrupt()</code>, one of two things happens. If that thread is executing a low-level interruptible blocking method like <code>Thread.sleep()</code>, <code>Thread.join()</code>, or <code>Object.wait()</code>, it unblocks and throws <code>InterruptedException</code>. Otherwise, <code>interrupt()</code> merely sets the thread's interruption status. Code running in the interrupted thread can later poll the interrupted status to see if it has been requested to stop what it is doing; the interrupted status can be read with <code>Thread.isInterrupted()</code> and can be read and cleared in a single operation with the poorly named <code>Thread.interrupted()</code>. </p>
<p>Interruption is a cooperative mechanism. When one thread interrupts another, the interrupted thread does not necessarily stop what it is doing immediately. Instead, interruption is a way of politely asking another thread to stop what it is doing if it wants to, at its convenience. Some methods, like <code>Thread.sleep()</code>, take this request seriously, but methods are not required to pay attention to interruption. Methods that do not block but that still may take a long time to execute can respect requests for interruption by polling the interrupted status and return early if interrupted. You are free to ignore an interruption request, but doing so may compromise responsiveness. </p>
<p>One of the benefits of the cooperative nature of interruption is that it provides more flexibility for safely constructing cancelable activities. We rarely want an activity to stop immediately; program data structures could be left in an inconsistent state if the activity were canceled mid-update. Interruption allows a cancelable activity to clean up any work in progress, restore invariants, notify other activities of the cancellation, and then termina