<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>漫漫长路，蓦然回首……</title>
    <description></description>
    <link>http://linbzh.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>hibernate零散经验整理</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/222472" style="color:red;">http://linbzh.javaeye.com/blog/222472</a>&nbsp;
          发表时间: 2008年07月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>基本上都是以前看书后写下的笔记和实践操作的记录。</p>
<p>&nbsp;</p>
<p><strong>一、关于查询迭代函数list.iterator(),Query.iterate()的比较<br /></strong>用hibernate进行查询，然后对查询结果进行迭代，有两种实现方法：<br />1、List ls = session.createQuery("...").list();<br />Iterator iter = ls.iterator();<br />while(iter.hasNext()){<br />//...<br />Object obj = (Object)iter.next();//以对象形式返回结果<br />//...<br />}<br />2、Iterator iter = session.createQuery("...").iterate();<br />//createQuery()返回Query类型<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一种查询方法list()函数，采用了一条语句直接查询了所有的结果；而第二种查询方法iterate()，则是先查询获得对象标识符(既是数据库主键)，然后根据对象标识符，对每个标识符生成相应的查询语句，进行查询并实例化持久对象。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外如果开启了二级缓存，第二种方法iterate()函数可以利用二级缓存，而list ()却只能利用到一级缓存。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于海量信息的查询用两种方法都可以能会有内存溢出的情况出。但iterate()方法是对每一条记录进行了查询并实例化持久对象的，这样就可以对每次查询获得的结果进行缓存清理，从而解决内存溢出的问题。<br />while(iter.hasNext()){<br />Object obj = (Object)iter.next();<br />session.evict(obj);//一级清理<br />sessionFactory.evict(Object.class,obj.getId());//二级清理<br />}</p>
<p><br /><strong>二、JOIN FETCH连接查询的限制</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如，A(a_id,name)和B(b_id,name,a_id)是一对多的关系，对应的HQL语句为:FROM A a JOIN FETCH a.B b那么返回的结果只会有左边的对象A的集合(返回的左边结果可能会有重复数据)，而右边的关联对象B则同父对象访问时获取。<br />1、不能使用Query.iterate()来取得结果集，iterate()不允许使用FETCH连接<br />2、不能在分页方法中使用，因为返回的左边结果的数据可能会重复，就无法获取正确的记录数。<br />3、不能带WITH条件，否则会抛出异常QuerySyntaxException</p>
<p>&nbsp;</p>
<p><strong>三、有关乐观锁</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 乐观锁的一般有两种实现方法：版本检查、时间截。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、版本检查要在对应的表添加版本号(version)字段（为整数类型），hibernate先会查询获取对应记录的verstion字段的值，在进行更新时，使用主键和先前所查得的version字段作为条件，并把version的值加1。如果主键和version对对应不到记录，更新失败，那么就会抛出异常。配置：&lt;class optimistic-lock="version" ...&gt;&lt;version name="vs" column="vs" type="java.lang.Integer"/&gt;&lt;/class&gt;。使用版本检查在一个系统使用，而其他的系统也对该数据库进行操作，并且该系统没有使用版本检查，就会导致数据的不一致。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、时间截也是采用同样的过程也是一样的，只是把version字段设置为date类型,配置&lt;class optimistic-lock="version" ...&gt;&lt;timestamp name="vs" column="vs"/&gt;&lt;/class&gt;，使用&lt;timestap&gt;节点一定要在&lt;id&gt;节点之后。由于时间的差异在并发线程同时读取和修改同一记录，可能导致数据的不一致，所以使用版本检查比较安全。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、如果是使用HQL语句进行更新，UPDATE语句是不会更新version字段的，需要使用versioned字段进行手工明确指定。update versioned A set name=:newName where name=:name</p>
<p>&nbsp;</p>
<p><strong>四、在批量更新和删除HQL语句中使用别名是无意义的</strong><br />UPDATE A SET name=:newName WHERE name=:name和UPDATE A a SET a.name=:newName WHERE a.name=:name生成的SQL是完全一样的：update A set name=? where name=?。如果该成UPDATE A a SET a.name=:newName WHERE a.name=:name AND a.B.name="123"就会生成sql语句：update A set name=? where name=? and name="123"，显然这个sql语句是错误的，并非所期望的结果。</p>
<p>&nbsp;</p>
<p><strong>五、HQL的DML及其insert</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; DML的insert不支持insert into values形式的插入操作，也不支持多态。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; DML即为数据操纵语言，对数据库的数据进行操作，而对象关系映射管理的对象状态是存在于内存的，所以执行DML批量操作并不会清理一级缓存，为了不得到脏数据，在执行批量操作时调用session.evict()清空一级缓存。</p>
<p>&nbsp;</p>
<p><strong>六、相同与不同的持久对象</strong><br />当是同一个session两次加载同一个主键记录时，生成的两个持久对象是相同的，可用==比较。<br />当是不同session各自加载同一个主键记录时，生成的两个持久对象是不同的。</p>
<p>&nbsp;</p>
<p><strong>七、性能提高</strong><br />1、提高Hibernate启动速度。使用Configuration.addCatcheableFile()方法提高启动速度。<br />2、&lt;class&gt;节点的属性dynamic-update的默认值为false，对所有的属性进行更新。修改为true，这样就只对更改了的属性进行更新。<br />3、绕过hibernate，直接使用JDBC或者存储过程来批处理数据时，同过session获得Connection对象，session.connection()，最后还要清理一级缓存中的数据，session.clear()，并不需要调用connection.close()关闭数据库连接，session会在关闭时关闭。<br />4、在循环中进行批量操作，可以这样<br />for(int i=0; i&lt;100000; i++){<br />//...<br />session.save(obj);<br />session.flush();<br />session.evict();<br />}<br />在上面已经提到，但性能提高并不大<br />可以这样做：<br />for(int i=0; i&lt;100000; i++){<br />//...<br />session.save(obj);<br />if(i%20==0){<br />session.flush();<br />session.evict();<br />}<br />}<br />5、使用DML风格的批量操作。[UPDATE|DELETE] FROM? EntityName [WHERE conditions?]，INSERT INTO EntityName properties_list SELETE selete_statement<br />6、在WEB应用中使用Open Sesion In View模式可以在MVC框架中实现延迟加载，安全关闭，避免频繁创建销毁。</p>
<p>&nbsp;</p>
<p><strong>八、有关查询缓存<br /></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 查询缓存是依赖于二级缓存的，查询结果较小，查询条件较稳定时方可以用查询缓存。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要在代码声明使用查询缓存，并设置区域，query.setCacheable(true);query.setCatcheRegion("abc");在对查询更改后，必须使用essionFactory.evictQueries("abc");清除查询缓存，否则会得到脏数据。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二级缓存的实现是以查询的HQL和查询参数作为key保持的，如果先后两个查询语句条件相近，查得的结果集相同或相近，第二个查询的部分结果集并不是在第一个查询结果集查找到的，而是重新全部从数据库加载。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如：from A a where a.age&gt;44和from A a where a.age&gt;42，两个查询语句条件相近，第一条查询结果集是第二条查询结果集的一部分，但是第二条查询部分结果集并不是从第一条查询结果集来的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以用OSCache控制缓存失效。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/222472#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Thu, 31 Jul 2008 22:11:01 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/222472</link>
        <guid>http://linbzh.javaeye.com/blog/222472</guid>
      </item>
      <item>
        <title>hibernate持久化对象操作</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/222470" style="color:red;">http://linbzh.javaeye.com/blog/222470</a>&nbsp;
          发表时间: 2008年07月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>闲着没事做，整理了hibernate持久化对象操作相关内容，供大家参考。</p>
<p>&nbsp;</p>
<p>一、由session缓存清理操作引起的问题<br />(一)session在一下不同的情况下进行清理操作：<br />1、在查询执行之前，如果发现缓存中的持久化对象属性发生了变化，session会先执行清理，保证查询的数据不脏数据。<br />2、在调用事务提交commit()的时候，commit()方法先清理缓存，然后再向数据库提交事务<br />3、调用session.flush()的时候，(与commit不同的是，flush()只是执行清理工作)。<br />(二)session执行清理sql语句的顺序<br />1、所有对持久对象进行插入的语句，其顺序按照调用session.save()的顺序；<br />2、所有对持久对象进行更新的语句；<br />3、所有进行集合删除的语句；<br />4、所有对集合元素进行删除、更新或插入的语句；<br />5、所有进行集合插入的语句；<br />6、所有对实体进行删除的语句，其顺序按照对象执行session.delete()的时间顺序。<br />(三)3种控制清理的方式：FlushMode.COMMIT只在事务提交时清理，按照缓存顺序执行；FlushMode.AUTO默认方式进行清理(Hibernate的默认方式)；lushMode.NEVER调用flush()方法时清理。通过session.setFlushMode()方法设定。<br />(四)引起的问题一，在执行事务提交前清除了相应的缓存数据。<br />session.evict(obj);transaction.commit();解决方法是在evict()前面加上flush()方法，或者把evict()放在commit()后面。<br />(五)引起的问题二，数据冲突<br />A a = new A();<br />a.setName("a");<br />session.save(a);<br />a.setName("b");<br />session.update(a);<br />A a1 = new A();<br />a1.setName("a");<br />session.save(a1);<br />session.flush();<br />由于session执行清理sql语句的顺序，先执行全部的插入语句，所以先执行了save(a)和save(a1)缓存的数据，再执行update(a)缓存的数据。解决方法是再update(a)后加上flush()函数或者采用FlushMode.COMMIT清理方式。</p>
<p>&nbsp;</p>
<p>二、save()函数<br />save()函数放在对持久化对象设置属性函数前，会多出update语句，例如<br />session.save(obj);<br />obj.setName("a");//对持久化对象的属性进行修改<br />会多出update A set name=? where id=?的语句，导致额外的开销。</p>
<p>&nbsp;</p>
<p>三、get()和load()函数<br />1、load()函数可以利用二级缓存，而get()不行；<br />2、如果没有匹配的记录，load()会抛出异常，get()不会；</p>
<p>&nbsp;</p>
<p>四、update()函数<br />update()函数的作用就是将脱管对象重新和Session进行关联，转换为持久对象，通知session生成一条UPDATE语句同步数据库，因为对脱管对象属性的修改不能反映到数据库中。并非与spring里面getHibernateTemplate().update()函数相同。<br />用update()把脱管对象重新session关联时，如果该session已经有了相同对象标识符的持久对象，就会抛出异常。除非在&lt;class&gt;节点配置属性select-before-update="true"，这样就会在update操作时生成一条select语句将数据库记录与需要更新的对象属性进行比较。不过对于经常更新的记录来说，配置该属性，在每次更新都会生成一条select语句，会降低应用程序的性能。</p>
<p>&nbsp;</p>
<p>五、lock()函数<br />lock()方法用处：用于版本检查；升级锁为悲观锁(lock(obj,LockMade.READ))；重新把游离实例于一个session实例相关联。<br />在执行lock方法时，会立即使用查询语句select查询版本号进行版本检查，不会执行一个update操作。而在执行update()方法时，并不会进行版本检查，直到执行flush方法，会先进行版本检查，在进行更新操作。</p>
<p>六、delete()、saveOrUpdate()函数</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/222470#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Thu, 31 Jul 2008 22:07:45 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/222470</link>
        <guid>http://linbzh.javaeye.com/blog/222470</guid>
      </item>
      <item>
        <title>hibernate的映射处理</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/222175" style="color:red;">http://linbzh.javaeye.com/blog/222175</a>&nbsp;
          发表时间: 2008年07月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最近闲着没事，就整理了hibernate的一些东西，供大家参考。<br /><strong><span style="color: #ff0000;">一、一对一关联在hibernate中的实现</span><br /></strong>一对一关联有两种实现方法：主键关联和外键关联。<br />主键关联是使两个表共享一个主键。比如，有表A和B，表A的主键为aid，那么表B</p>
<p>就把A的主键aid同时作为主键和外键使用。<br />A的映射文件：<br />&lt;class name="A" table="A"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="aId" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aid"&nbsp; length="10" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="guid"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="aname" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aname" length="10" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;one-to-one name="b" class="B" cascade="all"&gt;&lt;/one-to-one&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />cascade="all"表示级联操作，当cascade="false"时表示不进行级联操作。<br />&lt;one-to-one name="b" class="B" cascade="all"&gt;&lt;/one-to-one&gt;中的name="b"</p>
<p>在类A对应了属性b(类型为B);<br />B的映射文件：<br />&lt;class name="B" table="B" &gt;<br />&lt;id name="bId" type="java.lang.String"&gt;<br />&nbsp;&nbsp; &lt;column name="bid" /&gt;<br />&nbsp;&nbsp; &lt;!-- 使用foreign的主键生成方式，引用A对象的主键作为B对象的主键 --&gt;<br />&nbsp;&nbsp;&nbsp; &nbsp;&lt;generator class="foreign"&gt; <br />&nbsp;&nbsp;&nbsp; &nbsp;&lt;!-- 此a对应下面one-to-one的name名称一样 --&gt;<br />&nbsp;&nbsp;&nbsp; &nbsp;&lt;param name="property"&gt;a&lt;/param&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/generator&gt;<br />&lt;/id&gt;<br />&lt;property name="bname" type="java.lang.String"&gt;<br />&lt;column name="bname" length="20" /&gt;<br />&lt;/property&gt;<br />&lt;one-to-one name="a" class="A" constrained="true"&gt;&lt;/one-to-one&gt;<br />&lt;/class&gt;<br />&lt;one-to-one name="a" class="A" constrained="true"&gt;&lt;/one-to-one&gt;中的</p>
<p>name="a"在类B中对应了属性a(类型为A)<br />constrained="true"指明了B引用了A的主键作为外键，且是强制的一一对应关系。<br />使用外键关联，两个表都有各自的主键，比如，有表A和B，表A的主键为aid，那么表B就把A的主键aid同时作为外键使用。这种关联方法也可以用于一对多的关联。<br />A的映射文件：<br />&lt;class name="A" table="A"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="aId" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="aname" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aname" length="10" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;one-to-one name="b" class="B" cascade="all" property-</p>
<p>ref="a"&gt;&lt;/one-to-one&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />A的映射文件中的property-ref="a"是必须的，它跟B的映射文件中name="a"的&lt;many-to-one&gt;对应。<br />B的映射文件：<br />&lt;class name="B" table="B" &gt;<br />&lt;id name="bId" type="java.lang.String"&gt;<br />&nbsp;&nbsp; &lt;column name="bid"&nbsp; length="10" /&gt;<br />&nbsp;&nbsp;&nbsp; &nbsp;&lt;generator class="native"&gt;&lt;/generator&gt;<br />&lt;/id&gt;<br />&lt;property name="bname" type="java.lang.String"&gt;<br />&lt;column name="bname" length="20" /&gt;<br />&lt;/property&gt;<br />&lt;many-to-one name="a" class="A" unique="true" column="aid"/&gt;<br />&lt;/class&gt;</p>
<p>B的映射文件中的&lt;many-to-one name="a" class="A" unique="true" </p>
<p>column="aid"/&gt;指定了B的一个外键aid，unique="true"为外键aid生成一个唯一的约束，并使有一对一的关联关系。</p>
<p>对于一对一的检索策略，一般使用预先抓取，当另一端比较少使用时，可以使用延迟加载。<br />A.hbm.xml的&lt;one-to-one&gt;节点的fetch属性，A.hbm.xml的&lt;one-to-one&gt;节点的constrained属性，B.hbm.xml的&lt;class&gt;节点的lazy属性，不同的配置对应了不同的检索策略：<br />预先：无，无，无<br />预先：join，false，任意<br />立即：select，任意，任意<br />延迟：任意，true，true</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;"><strong>二、一对多关联在hibernate的单向关联实现</strong></span><br />一对多单向关联，它存在了一定的缺陷。<br />在hibernate中，在&ldquo;一&rdquo;的一端使用集合来实现对应关系，把&ldquo;一&rdquo;的一端作为控制方，而&ldquo;多&rdquo;的一端作为被控制方，&ldquo;多&rdquo;的一端不需要任何特殊的配置。被控制方并不知道控制方是谁。例如，表A是&ldquo;一&rdquo;的一端，表B是&ldquo;多&rdquo;的一端。<br />A的映射文件：<br />&lt;class name="A" table="a" &gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="aId" type="java.lang.Integer"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="name" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="name" length="10" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;set name="bs" order-by="bid" cascade="all" fetch="join"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;key column="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;one-to-many class="B"&gt;&lt;/one-to-many&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />order-by="bid"指定了排列顺序<br />&lt;set ...&gt;&lt;/set&gt;在类A中对应了属性bs（类型为HashSet&lt;B&gt;）<br />&lt;one-to-many class="B"&gt;&lt;/one-to-many&gt;指定了&ldquo;多&rdquo;的一端&lt;key column="aid" /&gt;指定了&ldquo;多&rdquo;一端的外键。<br />B的映射文件：<br />&lt;class name="B" table="b" &gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="bId" type="java.lang.Integer"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="bid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="aId" type="java.lang.Integer"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&lt;/class&gt;<br />当A进行级联操作时，hibernate就会执行大量的sql语句，大大地影响了性能(可以在hibernate.cfg.xml设置&lt;property </p>
<p>name="hibernate.jdbc.batch_size"&gt;30&lt;/property&gt;实现批量更新，这个值一般取5～30)。如果把映射文件A中的&lt;key column="aid" /&gt;设为&lt;key column="aid" not-null="true" /&gt;则在级联删除时会抛出异常，因为在删除表B的记录之前会把aid设为NULL。</p>
<p>一对多关联的检索策略，优先考虑延迟加载，不同的&lt;set/&gt;的属性fetch，lazy的值，对于不同的检索策略<br />延迟：select，true<br />立即：select，false<br />预先：join，任意</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;"><strong>三、一对多（多对一）关联在hibernate的双向关联实现<br /></strong></span>一对多（多对一）双向关联，在两端都知道各自的对方，解决了单向关联的缺陷。<br />一对多（多对一）双向关联，一般把&ldquo;多&rdquo;的一端作为控制方，如果把&ldquo;一&rdquo;的一端作为控制方的话，当加载&ldquo;一&rdquo;的一端的一条记录时就会加载&ldquo;多&rdquo;的一端相关的所有记录，这样就会影响性能。<br />例如，表A是&ldquo;一&rdquo;的一端，表B是&ldquo;多&rdquo;的一端。<br />A的映射文件：<br />&lt;class name="A" table="a" &gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="aId" type="java.lang.Integer"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="name" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="name" length="10" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;set name="bs" order-by="bid" cascade="all" lazy="true" </p>
<p>inverse="true"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;key column="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;one-to-many class="B"&gt;&lt;/one-to-many&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />inverse="true"，标识了被控制方一端，inverse="false"的一方为控制方，负责维护关联关系。<br />&lt;set name="bs" ...&gt;&lt;/set&gt;在类A中对应了属性bs（类型为java.util.HashSet&lt;B&gt;）<br />B的映射文件：<br />&lt;class name="B" table="B" &gt;<br />&lt;id name="bId" type="java.lang.String"&gt;<br />&nbsp;&nbsp; &lt;column name="bid" /&gt;<br />&nbsp;&nbsp;&nbsp; &nbsp;&lt;generator class="native"&gt;&lt;/generator&gt;<br />&lt;/id&gt;<br />&lt;property name="bname" type="java.lang.String"&gt;<br />&lt;column name="bname" length="20" /&gt;<br />&lt;/property&gt;<br />&lt;many-to-one name="a" class="A" column="aid" cascade="none"/&gt;<br />&lt;/class&gt;<br />&lt;many-to-one name="a" class="A" column="aid" cascade="none"/&gt;指定了外键aid，name="a"对应了类B中的属性a(类型为A)inverse的默认值为false。</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;"><strong>四、多对一关联在hibernate的单向关联实现</strong></span><br />多对一单向关联。在hibernate中，在&ldquo;多&rdquo;的一端使用集合来实现对应关系，把&ldquo;多&rdquo;的一端作为控制方，而&ldquo;一&rdquo;的一端作为被控制方，&ldquo;一&rdquo;的一端不需要任何特殊的配置。被控制方并不知道控制方是谁。例如，表A是&ldquo;一&rdquo;的一端，表B是&ldquo;多&rdquo;的一端。<br />A的映射文件：<br />&lt;class name="A" table="a" lazy="false"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="aId" type="java.lang.Integer"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="name" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="name" length="10" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/class&gt;</p>
<p>B的映射文件：<br />&lt;class name="B" table="b" &gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="bId" type="java.lang.Integer"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="bid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;many-to-one name="a" class="A" &gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key column name="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&lt;/class&gt;<br />&lt;many-to-one name="a" class="A" &gt;对应了在类B的属性a(类型为A)可见，在&ldquo;一&rdquo;的一端相应的类A，并没有集合属性，类A不能获取&ldquo;多&rdquo;的一端对应的记录，这是多对一单向关联的特点。</p>
<p>对于多对一关联的检索策略，和一对一关联一样，也是首先考虑预先抓取，如果&ldquo;一&rdquo;的一端不常用，就用延迟加载检索策略。<br />B.hbm.xml的&lt;many-to-one&gt;节点的fetch属性，B.hbm.xml的&lt;many-to-one&gt;节点的lazy属性，A.hbm.xml的&lt;class&gt;节点的lazy属性，不同的配置对应不同的策略：<br />预先：join，任意，false<br />预先：无，无，false<br />延迟：任意，proxy，true<br />立即：任意，false，任意<br />立即：select，任意，false</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;"><strong>五、多对多关联在hibernate的实现</strong></span><br />如果两个表是多对多的关系，就需要一个中间表来实现多对多的对应关系。多对多关系是双向的。<br />&lt;class name="A" table="a" &gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="aId" type="java.lang.Integer"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"&gt;&lt;/generator&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="name" type="java.lang.String"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="name" length="10" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;set name="bs" table="a_b" cascade="save_update" </p>
<p>inverse="false" lazy="true"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;key column="aid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;many-to-many class="B" column="bid"&gt;&lt;/many-to-many&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />&lt;set name="bs" ...&gt;&lt;/set&gt;在类A中对应了属性bs（类型为HashSet&lt;B&gt;）<br />&lt;key column="aid" /&gt;指定了在表a_b中的字段aid为表A的主键aid<br />&lt;many-to-many class="B" column="bid"&gt;&lt;/many-to-many&gt;指定了另一端</p>
<p>B的映射文件：<br />&lt;class name="B" table="B" &gt;<br />&lt;id name="bId" type="java.lang.String"&gt;<br />&nbsp;&nbsp; &lt;column name="bid" /&gt;<br />&nbsp;&nbsp;&nbsp; &nbsp;&lt;generator class="native"&gt;&lt;/generator&gt;<br />&lt;/id&gt;<br />&lt;property name="bname" type="java.lang.String"&gt;<br />&lt;column name="bname" length="20" /&gt;<br />&lt;/property&gt;<br />&lt;set name="as" table="a_b" cascade="save_update" fetch="join" </p>
<p>lazy="true"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;key column="bid" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;many-to-many class="A" column="aid"&gt;&lt;/many-to-many&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;<br />&lt;/class&gt;<br />&lt;set name="as" ...&gt;&lt;/set&gt;在类B中对应了属性as（类型为HashSet&lt;A&gt;）</p>
<p>多对多关联的检索策略，优先考虑延迟加载，不同的&lt;set/&gt;的属性fetch，lazy的值，对于不同的检索策略<br />延迟：select，true<br />立即：select，false<br />预先：join，任意</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;"><strong>六、集合映射</strong></span><br />有Map，集合中的每个元素都包好一对关键字和值对象，集合中的关键字不能重复；Set，集合中的每个元素都不会重复，可以是一个null对象，加入Set的元素都必须重新定义equals和hashCode方法，以便元素进行排序；List，是有序的排列</p>
<p>集合，允许元素重复，可以通过索引访问元素；Bag也是集合，允许元素重复，是无序的；idbag在bag在基础上添加了collection-id，是hibernate可以直接操作要更新的数据，提高效率。</p>
<p>每个集合映射值类型的配置都有相同之处：<br />&lt;xxx name="" table=""&gt;&lt;key column=""/&gt;&lt;element column="" type=""/&gt;&lt;/xxx&gt;</p>
<p>&nbsp;</p>
<p>对于映射实体类型的配置：<br />bag和idbag没有映射实体类型；<br />Map和List有一个&lt;index column="" type=""/&gt;节点，Map的index节点是指定Map的key，List的index节点是维护排序的，正因为Map和List需要index节点，在设置inverse="true"时，保存集合中对象时，无法设置index的值，所以Map和List无法使用inverse="true"来实现的&ldquo;多&rdquo;端作为控制方，这样会影响性能；</p>
<p>&nbsp;</p>
<p>集合的排列：<br />数据库读取时排列：在每个映射配置上加order-by属性，list不支持该属性；<br />读取后进行内存排列：使用sort属性，只有Map和set支持该属性。</p>
<p>&nbsp;</p>
<p>值类型没有自己的生命周期，它依赖于附属的实体，随着实体的消亡而消亡；而实体类型作为一个独立的实体存在，有自己的生命周期。使用值类型不可以实现延迟加载会影响性能，而实体类型可以实现。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/222175#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Thu, 31 Jul 2008 13:35:46 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/222175</link>
        <guid>http://linbzh.javaeye.com/blog/222175</guid>
      </item>
      <item>
        <title>NULL Object空对象模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/216257" style="color:red;">http://linbzh.javaeye.com/blog/216257</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL Object空对象模式：当你在处理可能会出现null的对象时，可能要产生相对乏味的代码来做相应的处理，使用空对象模式可以接受null，并返回相应的信息。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 空对象模式通常会作为一个单独的空对象类，封装一个默认的行为。</p>
<pre name="code" class="java">Interface Log{public void log();}
class FileLog extends Log{public void log(){}}
class ConsoleLog extends Log{public void log(){}}
class NullObjectLog extends Log{public void log(){}}
public class Test{
  static Log fun(String str){
  Log log = new NullObjectLog();
  if("file".equals(str)) log = new FileLog();
  if("console".equals(str)) log = new ConsoleLog();
  return log;
}
public static void main(String []args){
  Log log = fun();
  log.log("message");
}
}
</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/216257#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Fri, 18 Jul 2008 17:09:51 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/216257</link>
        <guid>http://linbzh.javaeye.com/blog/216257</guid>
      </item>
      <item>
        <title>proxy代理模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/213915" style="color:red;">http://linbzh.javaeye.com/blog/213915</a>&nbsp;
          发表时间: 2008年07月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy代理模式，其意图是"为其他对象提供一种代理以控制对这个对象的访问"，通俗的讲就是，一个类A请一个代言人C去跟另一个类B打交道。在"四人帮"的《设计模式》中代理一章有关代理的"动机"的那节，举文档编辑器加载图像为例，说得很形象、透彻。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 根据不同的用途，proxy代理模式又可以分为：远程代理、虚代理、访问控制（保护）代理、引用代理、审计代理、同步化代理、copy-on-write代理、缓存代理。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 远程代理：提供访问远程对象的途径（RMI的应用）。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;虚代理：由于创建目标对象的内存资源开销很大，延迟对该资源的访问，只有在用到的时候才被创建出来。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;访问控制代理：控制对原始对象的访问。通过设置不同的允许策略，控制不同客户对代理的特定部分的访问控制，保证对象应该有不同的访问权限。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 引用代理：维护一个对目标对象的引用计数，只有当没有客户在使用目标对象时才去删除它。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 审计代理：在执行目标对象的一个方法之前或者之后做一些审计的行为。也就是AOP编程。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同步化代理：防止若干个客户对象对目标对象的并行访问，在真正访问之前检查目标对象是否被锁定。类似于数据库的事务锁。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy-on-write代理：类似于virtual proxy虚代理，把拷贝延迟到只有客户需要时，才真正采取行动。在《设计模式》中描述得很清楚："拷贝一个庞大而复杂的对象是一种开销很大的操作，如果这个拷贝根本没有被修改，那么这些开销就没有必要。用copy-on-write代理可以延迟这一过程，可以保证只有当这个对象被修改时才对它进行拷贝。在实现copy-on-write代理是必须对实体进行引用计数。拷贝代理会增加引用计数。只有当用户请求一个修改该实体的操作时，代理才会真正的拷贝它，在这种情况下，代理还必须减少实体的引用计数。当引用的数目为零时，这个实体将被删除。"。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;缓存代理：为某一个目标操作的结果提供临时的存储空间，以便多个客户可以共享这些结果，而不必去访问实际对象，可以获得一个更快的响应时间。类似于flyweight享元模式。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/213915#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Fri, 11 Jul 2008 14:15:58 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/213915</link>
        <guid>http://linbzh.javaeye.com/blog/213915</guid>
      </item>
      <item>
        <title>visitor访问者模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/212084" style="color:red;">http://linbzh.javaeye.com/blog/212084</a>&nbsp;
          发表时间: 2008年07月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; visitor访问者模式的意图，在《设计模式》里这样描述：&ldquo;表示一个作用于某个对象结构中的各元素的操作。它使可以在不改变各元素的类的前提下定义作用于这些元素的新操作。&rdquo;。就是说：在坚持&ldquo;开闭原则&rdquo;的情况下，访问者可以用来扩展一个现有的类层次结构来实现新的行为。更通俗的讲，如果不愿意修改类层次结构内部代码或者类层次结构的代码难以修改的情况下，如果该类层次结构在设计实现时使用了visitor访问者模式，那么可以实现&ldquo;在不修改类层次结构代码的前提下&rdquo;进行扩展。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 但是visitor访问者模式是一个有争议的模式，在《Design Paterns Java Workbook》（作者Steven John Metsker）里提到了三种代替方案。</p>
<p>《Software Architecture Design Patterns in Java》中的例子：</p>
<pre name="code" class="java">public interface VisitorInterface {
  public void visit(NonCaliforniaOrder nco);
  public void visit(CaliforniaOrder co);
  public void visit(OverseasOrder oo);
}

public class OrderVisitor implements VisitorInterface {
  private double orderTotal;
  public OrderVisitor() {
  }
  public void visit(NonCaliforniaOrder inp_order) {
    orderTotal = orderTotal + inp_order.getOrderAmount();
  }
  public void visit(CaliforniaOrder inp_order) {
    orderTotal = orderTotal + inp_order.getOrderAmount() +
                 inp_order.getAdditionalTax();
  }
  public void visit(OverseasOrder inp_order) {
    orderTotal = orderTotal + inp_order.getOrderAmount() +
                 inp_order.getAdditionalSH();
  }
  public double getOrderTotal() {
    return orderTotal;
  }
}
public class OverseasOrder implements Order {
  private double orderAmount;
  private double additionalSH;

  public OverseasOrder() {
  }
  public OverseasOrder(double inp_orderAmount,
      double inp_additionalSH) {
    orderAmount = inp_orderAmount;
    additionalSH = inp_additionalSH;
  }
  public double getOrderAmount() {
    return orderAmount;
  }
  public double getAdditionalSH() {
    return additionalSH;
  }
  public void accept(OrderVisitor v) {
    v.visit(this);
  }
}
public class CaliforniaOrder implements Order {
  private double orderAmount;
  private double additionalTax;

  public CaliforniaOrder() {
  }
  public CaliforniaOrder(double inp_orderAmount,
      double inp_additionalTax) {
    orderAmount = inp_orderAmount;
    additionalTax = inp_additionalTax;
  }
  public double getOrderAmount() {
    return orderAmount;
  }
  public double getAdditionalTax() {
    return additionalTax;
  }
  public void accept(OrderVisitor v) {
    v.visit(this);
  }
}
public class NonCaliforniaOrder implements Order {
  private double orderAmount;

  public NonCaliforniaOrder() {
  }
  public NonCaliforniaOrder(double inp_orderAmount) {
    orderAmount = inp_orderAmount;
  }
  public double getOrderAmount() {
    return orderAmount;
  }
  public void accept(OrderVisitor v) {
    v.visit(this);
  }
}</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/212084#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 06 Jul 2008 18:23:17 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/212084</link>
        <guid>http://linbzh.javaeye.com/blog/212084</guid>
      </item>
      <item>
        <title>command命令模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/207235" style="color:red;">http://linbzh.javaeye.com/blog/207235</a>&nbsp;
          发表时间: 2008年06月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: x-small;"> </span><span style="font-size: small;">command命令模式，将请求封装成对象，通过对象的形式来实现对请求的控制，例如排序、执行和取消等。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; command命令模式也是一个遵循开闭原则的模式，避免了传统的if else的硬代码，又可以容易地把新的命令加入系统。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 先声明一个公共接口，各个命令各自实现该接口。要使用该命令时，触发该命令或者向命令的使用者注册该命令，执行相应的方法即可。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #888888;">使用javaSE5的新类型枚举(Enum)，结合EnumMap（键－值方式存储）构造命令模式也是一个不错的选择，这样可以使代码更加简洁，清晰。<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;基本的代码框架：</span></p>
<pre name="code" class="java">public interface Command{
   public void execute();
}

public CommandOne implements Command{
   public void execute(){}
}

public CommandTwo implements Command{
   public void execute(){}
}

public class Execute{
   public Command command;
   public Execute(Command command){this.command = command;}
   public void execute(){command.execute();}
}
</pre>
<pre name="code" class="java">import java.util.*;
import static java.lang.System.*;
interface Command{
   public void execute();
}
enum CommandEnum{
   A,B
}
public class Test{
   static EnumMap&lt;CommandEnum,Command&gt; mp = new EnumMap&lt;CommandEnum, Command&gt;(CommandEnum.class);
   static void execute(CommandEnum ce){
     mp.get(ce).execute();
}
   public static void main(String []args){
     mp.put(CommandEnum.A,new Command(){public void execute(){out.println("command A");}});
     mp.put(CommandEnum.B,new Command(){public void execute(){out.println("command B");}});
     execute(CommandEnum.A);
   }
}</pre>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/207235#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 23 Jun 2008 22:13:51 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/207235</link>
        <guid>http://linbzh.javaeye.com/blog/207235</guid>
      </item>
      <item>
        <title>template method模版方法模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/207183" style="color:red;">http://linbzh.javaeye.com/blog/207183</a>&nbsp;
          发表时间: 2008年06月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template method模版方法模式，说白了，就是抽象类的运用。模版方法模式很多时候都在用，利用该模式可以实现提高代码的复用率。它把各子类相同的方法放在抽象类，避免了编写重复的代码，而其他可变的方法强制型地在各子类各自实现，实现代码规范性。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在我们使用的一些软件包的时候，有一些要求我们继承其某个类，并实现其方法，例如struts的Action，要求实现execute方法。原因是在Action内部定义了一个实现其功能的代码架构，用户不必做其他的事情，只要在继承并实现execute方法即可。这样做的目的是使得代码有规范性，简化代码，并达到方便用户使用的目的。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/207183#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 23 Jun 2008 17:49:57 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/207183</link>
        <guid>http://linbzh.javaeye.com/blog/207183</guid>
      </item>
      <item>
        <title>state状态模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/206928" style="color:red;">http://linbzh.javaeye.com/blog/206928</a>&nbsp;
          发表时间: 2008年06月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state状态模式，在代码的结构上跟策略模式没什么区别，只是它们的应用则重点不同。一个对象的行为依赖以一些状态的变化而随之变化，一种传统的做法就是if else的条件判定硬代码，这样的代码级不美观，也不好扩展维护。采用state状态模式就是把各个不同状态的所以执行的代码分别放到不同的类中。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/206928#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Sun, 22 Jun 2008 22:40:03 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/206928</link>
        <guid>http://linbzh.javaeye.com/blog/206928</guid>
      </item>
      <item>
        <title>strategy策略模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/203091" style="color:red;">http://linbzh.javaeye.com/blog/203091</a>&nbsp;
          发表时间: 2008年06月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strategy策略模式,策略即算法，策略模式是对算法的封装，把使用算法的使用者和算法本身分割开，分派给不同的对象管理。一系列的算法封装到一系列的策略类里面，作为一个抽象策略类的子类或接口的实现类。换句话说：就是准备一组算法，当条件或环境变化，需要不同的算法时，则向算法的使用者注册该算法，使得其可以在使用者的内部使用该算法。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 传统的作法，是使用if else语句在方法中实现并选择不同的算法（很多使用面向对象语言编写程序的人还是停留在结构化的思维定势），这与面向对象的开闭原则是不符的。在大量if else的代码环境下是比较难以维护排错的和扩展的，使用策略模式也可以提高代码复用率，并且使用者不必涉及到任何的算法代码，只涉及到算法的输入输出值。当要添加算法时，只要写一个封装该算法的类并向使用者注册即可。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另一种面向对象思想的作法，就是实现使用者的不同子类，有多少策略就派生出多少个子类。而这样会导致子类的膨胀。可能会出现不必要的复杂结构，代码复用性也做得不好。</p>
<pre name="code" class="java">public interface Strategy {
  public String mystrategy(String input);
}
public class StrategyA implements Strategy{
  public String mystrategy(){/*...*/return "a";}
}
public class StrategyB implements Strategy{
  public String mystrategy(){/*...*/return "b";}
}
public class Myclass{
  private Strategy s;
  public Myclass(){s=new StrategyA();}
  public setStrategy(Strategy s){this.s=s;}
  public useStrategy(){System.out.println(s.mystrategy());}
}
public class Main(){
  public static void main(String args[]){
    Myclass mc = new Myclass();
    mc.setStrategy(new StrategyB());
    mc.useStrategy();
  }
}</pre>
<p>可以与工厂模式结合使用。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/203091#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Fri, 13 Jun 2008 20:08:44 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/203091</link>
        <guid>http://linbzh.javaeye.com/blog/203091</guid>
      </item>
      <item>
        <title>observer观察者模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/202052" style="color:red;">http://linbzh.javaeye.com/blog/202052</a>&nbsp;
          发表时间: 2008年06月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; observer观察者模式，取名为观察者可能会让人费解，该模式的思想跟订阅/发布服务的思想是相近的，所以称为订阅/发布模式更为通俗贴切。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 存在着这样的类：类A的某个状态发生改变，或者触发了某个事件，会影响到其他的n个类(一般是实现了相同的接口)的状态；或者n个类的某些状态是在某一时刻内&ldquo;同时&rdquo;发生的。一种不明智的作法就是，在类A中编写硬代码，如果n增加了，就要向类A添加相应的代码，并且这些代码会是跟前n-1次前添加的基本上是一样的。</p>
<pre name="code" class="java">public class Observable {
  private ObserverA a;
  private ObserverB b;
  /*a,b的geter/seter ......*/
  public void setA(ObserverA a){this.a=a;}
  public Observable(){/*...*/} 
  public void notifyObservers(){
     a.refreshData();
     b.refreshData();
  }
}
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果ObserverA和ObserverB的接口不一样，那么就只能这么做了(但也许可以用适配器来解决)。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有发布类A，和订阅类B、C等若干个类，实例化这若干个类后，向A注册这些订阅类实例，当发布类A执行某些操作并需要通知向A注册的若干个订阅类时，则通过调用类A相应的函数来实现。订阅者也可以取消注册。一般不同的订阅者是实现相同的接口。<br />一般架构：</p>
<pre name="code" class="java">public class Observable {
  private Vector observerList;
  public Observable(){/*...*/} 
  public void notifyObservers(){
      for (int i = 0; i &lt; observersList.size(); i++) {
      Observer observer = (Observer) observersList.elementAt(i);
      observer.refreshData();
    }
  }
  public void register(Observer obs){observersList.addElement(obs);}
  public void unRegister(Observer obs){/*...*/}
}

public interface Observer {
  public void refreshData();
}
public class ObserverA implements Observer{
  public ObserverA(Observable observable){observable.register(this);}
  public void refreshData(){/*...*/}
}
public class ObserverB implements Observer{
  public ObserverB(Observable observable){observable.register(this);}
  public void refreshData(){/*...*/}
}
</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/202052#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Wed, 11 Jun 2008 10:50:04 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/202052</link>
        <guid>http://linbzh.javaeye.com/blog/202052</guid>
      </item>
      <item>
        <title>poi的一个让人失望的bug</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/201502" style="color:red;">http://linbzh.javaeye.com/blog/201502</a>&nbsp;
          发表时间: 2008年06月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用poi读取ws的ppt文件时，会抛出Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 8的异常。（使用版本poi-3.0.2）。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 解决办法是，打开项目的properties-&gt;java build path-&gt;order and export，发现poi放到了最后，把poi的包上移。问题解决！</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 上面的问题解决之后，再读取ws的word文件是，就会抛出java.lang.StringIndexOutOfBoundsException: String index out of range: -86的异常。解决办法是，打开项目的properties-&gt;java build path-&gt;order and export，把poi的包下移到最后。问题解决！</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如果用的是poi-3.1的话，会抛出Exception in thread "main" java.lang.NoSuchMethodError: org.apache.poi.poifs.filesystem.POIFSFileSystem.getRoot()Lorg/apache/poi/poifs/filesystem/DirectoryNode;的异常，解决方法是把org/apache/poi/poifs/filesystem的class文件提取出来，放在bin里面，之后还是抛出java.lang.StringIndexOutOfBoundsException和java.lang.ArrayIndexOutOfBoundsException的异常。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;综上，要在同一个项目用poi同时读取word和ppt文件，会出现异常。除非你的work文件只有半页纸不到的内容。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/201502#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 09 Jun 2008 14:57:38 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/201502</link>
        <guid>http://linbzh.javaeye.com/blog/201502</guid>
      </item>
      <item>
        <title>memento备忘录模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/201418" style="color:red;">http://linbzh.javaeye.com/blog/201418</a>&nbsp;
          发表时间: 2008年06月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memento备忘录模式，就是利用平常所说的备忘录的思想，把一些可能在以后要用到的东西先记起来，等到要用的时候就可以查询备忘录，再次利用。在软件设计中就是将对象的状态存储起来，根据需要，这个对象只要向备忘录发出一个请求就能够从备忘录读取数据并恢复到先前的状态。<br />&nbsp;&nbsp;&nbsp;&nbsp; 既然是备忘录就会有一个或以上的信息来源，一条或以上的记录和一个记录集（记录管理）。需要存储信息的对象就是信息的来源。<br />&nbsp;&nbsp;&nbsp;&nbsp; 因为隐私的原因，备忘录只有，记录人才能看到。同样的，备忘录对象必须对源发者之外的对象隐藏该原发者的内部变量的值。所以，在java中，记录类一般设计为内容类。<br />&nbsp;&nbsp;&nbsp;&nbsp; 对于数据的储存方式，在"j道"写道："设计模式之Memento:很简单一个模式,就是在内存中保留原来数据的拷贝. "，应不然，对于存储的方式应该根据不同的需要可以选择不同的形式，持久或者非持久。</p>
<p>一般架构：</p>
<pre name="code" class="java">//源发者，信息来源
public class Originator{
    private String state;
    public Memento createMemento(){//创建记录
       return new Memento( this.state );
   }
   public void restoreMemento(Memento memento){//恢复记录
       this.setState(memento.getState());
   }
   public String getState(){//获取记录
       return this.state;
   }
   public void setState(String state){//设置记录
       this.state = state;
   }
   //记录
  class Memento {
        private String savedState;
           private Memento(String someState){
               savedState = someState;
           }
           private void setState(String someState){
               savedState = someState;
           }
           private String getState(){
               return savedState;
           }
     }
}
//简单记录集（记录管理）
public class Caretaker{
    private Memento memento;
    public Memento retrieveMemento(){//获取记录
        return this.memento;
   }
    public void saveMemento(Memento memento){//保存记录
        this.memento = memento;
   }
}
//多记录集（记录管理）
public class Caretaker{
    private Originator originator;
    private Vector mementos = new Vector();
    private int total;
    public Caretaker(Originator originator){ 
        this.originator = originator;
        total= 0;
    }
    public void createMemento(){ //创建
     Memento memento = this.originator.createMemento();
        mementos.addElement(memento);
        total++;
    }
   public void saveMemento(Memento memento){//保存记录
     mementos.addElement(memento);
        total++;
   }
    public void retrieveMemento(int index){ //获取
      Memento memento = (Memento) mementos.elementAt  (index);
        originator.restoreMemento(memento);
    }
    public void removeMemento(int index){//删除
     mementos.removeElementAt(index);
        total--;
   }
}
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在web程序中的session是mememto备忘录模式应用的一个典型例子。由servlet的session的函数setAttribute</p>
<p>(String,Object)和函数getAttribute(String)，可以看出session的内部实现应该是利用一个哈希表储存对象状态的。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/201418#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 08 Jun 2008 21:34:18 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/201418</link>
        <guid>http://linbzh.javaeye.com/blog/201418</guid>
      </item>
      <item>
        <title>mediator中介者模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/199582" style="color:red;">http://linbzh.javaeye.com/blog/199582</a>&nbsp;
          发表时间: 2008年06月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mediator中介者模式，用来管理很多对象之间的相互作用，将一系列对象中对象之间传递消息的细节封装在一个独立的类中，从而减少这些对象之间直接交互所带来的复杂度，和集成测试的难度。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mediator调停者模式，是用在这种情况下的，有n个对象，他们之间形成了复杂的相互引用的关系，在最坏的情况下，可能形成了n*(n-1)/2的关系链，随着n的增大，n*(n-1)/2也就随之不断递增，从而就形成了一种高耦合的复杂结构。如果用一个调停者来管理这些对象之间相互作用带来的复杂关系，对象之间的交互通过调停者进行间接的传递消息，从而减少对象之间直接作用的复杂度，最终实现解耦的目的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这n个对象中的对象要向其他对象发送消息时，就向mediator类注册，然后执行相应的方法，实现消息的传递。</p>
<pre name="code" class="java">public class Aclass{
}
public class Bclass{
}
public class Cclass{
}
public class Mediator{
    private Aclass a;
    private Bclass b;
    private Cclass c;
    public void registerA(Aclass a){
        this.a=a;
    }
    public void registerA(Bclass b){
        this.b=b;
    }
    public void registerC(Bclass c){
        this.b=b;
    }
    public void execute1(){
    }
    public void execute2(){
   }
}</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/199582#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 03 Jun 2008 00:32:12 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/199582</link>
        <guid>http://linbzh.javaeye.com/blog/199582</guid>
      </item>
      <item>
        <title>interator迭代模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/198914" style="color:red;">http://linbzh.javaeye.com/blog/198914</a>&nbsp;
          发表时间: 2008年05月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; interator迭代模式，学过数据结构的，都知道迭代是怎么一回事，最简单的链表也是用到迭代来一个一个地读取数据。利用迭代模式来读取一系列按一定规则来存储的数据，而你不必理会封装的数据存储的结构是怎么样的，一般都会提供一个叫next的函数，要读取数据，只要next个若干次就行了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果原本是对List编码的，但后来要修改为Set，如果你在读取元素的地方使用了Iterator，那么就不用修改此处的代码，这一点在《java编程思想》也提到了。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/198914#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Sat, 31 May 2008 10:13:39 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/198914</link>
        <guid>http://linbzh.javaeye.com/blog/198914</guid>
      </item>
      <item>
        <title>ChainOfResponsiblity责任链模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/197518" style="color:red;">http://linbzh.javaeye.com/blog/197518</a>&nbsp;
          发表时间: 2008年05月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>ChainOfResponsiblity责任链模式。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一系列对象之间的消息传递形成了线性的或循环的传递结构，例如A可以传给B，B可以传给C，C可以传给D&hellip;&hellip;当条件不满足传递时，就停止传递。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如，客户端对象发出一个请求给服务端处理，而客户端只知道服务端有n个服务对象可以对这个请求作出响应，但是客户端并不清楚哪个服务端对象是最合适处理这个请求的。最原始的处理方式，就是在客户端程序进行n个if else的语句判断。当服务端在添加一个服务处理对象时，便在客户端再添加一个if else，就这样如此循环不断的进行下去。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可见这样的代码的质量相当低劣，是如何的不高明，难以维护扩展。利用责任链的作法是，在客户端创建出那些可以对请求作出响应的服务端的对象实例，然后设置服务对象之间的传递关系，接着把请求消息传递给第一个服务对象，交给服务对象之间进行内部判断究竟哪个是适合作出响应的。其中服务对象之间的传递关系的实现，类似于单向链表的实现。</p>
<pre name="code" class="java">public abstract class Service{
  private Service nextService;
  public Service() {/*...*/}
  public abstract void response(Request request);
  public Service getNextService() {
    return nextService;
  }
  public void setNextService(Service service) {
    nextService = service;
  };
}
class FService extends Service {
  private int flag = 1;
  public FService() {/*...*/}
  public void response(Request request) {
    int flag = request.getFlag();
    if (flag == this.flag) {
      System.out.println("响应");
    } else {
      getNextService().response(request);
    }
  }
}

class SService extends Service {
  private int flag = 2;
  public SService() {/*...*/}
  public void response(Request request) {
    int flag = request.getFlag();
    if (flag == this.flag) {
      System.out.println("响应");
    } else {
      getNextService().response(request);
    }
  }
}
public class Client{
  private static Request request = null;
  private static FService fs = null;
  private static SService ss = null;
  public static void main(String[] args) {
    request = new Request(2);
    fs = new FSservice();
    ss = new SService();
    fs.setNextService(ss);
    fs.response(request );
  }
}
class Request{
  prviate int flag;
  public Request(int flag){this.flag = flag;}
  public int getFlag(){return this.flag;}
}</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其实，以<span style="color: #ff0000;">servlet中的filter</span>作为责任链的经典例子，是最好不过的了。过滤器的实现跟上面的例子有所不同，首先每个过滤器向一个过滤器链的管理器FilterChain注册，在每个过滤器Filter的doFilter(ServletRequest request,ServletResponse response,FilterChain chain)方法里面调用FilterChain的chain.doFilter(request,response);方法，由FilterChain实现调用下一个过滤器。实现的代码大概如下：</p>
<pre name="code" class="java">public interface Filter{
  public void init(FilterConfig config) throws ServletException;
  public void doFilter(ServletRequest srequest,ServletResponse   sresponse,FilterChain chain)throws       IOException,ServletException;
  public void destroy();
}
public FilterChain{
  private List list = new Vector();
  private int currentFilter = 0;
  private int totalFilter = 0;
  public void addFilter(Filter filter){
    list.add(filter);
    totalFilter++;
  }
  public void doFilter(ServletRequest request,ServletResponse response){
    /*......*/
    if(currentFilter==totalFilter)
       return;
    ((Filter)list.get(currentFilter++)).doFilter();
    /*......*/
  }
}
public class MyFilter implements Filter {
　public void init(FilterConfig config) throws ServletException {/*...*/}
　public void destroy(){/*...*/}
　public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
 throws IOException,ServletException {/*...*/chain.doFilter();}
}</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/197518#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 27 May 2008 17:04:47 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/197518</link>
        <guid>http://linbzh.javaeye.com/blog/197518</guid>
      </item>
      <item>
        <title>facade外观模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/196613" style="color:red;">http://linbzh.javaeye.com/blog/196613</a>&nbsp;
          发表时间: 2008年05月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; facade外观模式，简单明了的讲是，子系统封装聚集模式。facade外观模式遵循了迪米特法则，体现了松耦合原则。facade所面对的往往是多个类或其它程序单元，通过重新组合各类及程序单元，对外提供统一的接口，以便维护管理，减少复杂度和依赖性。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff0000;">facade外观模式有点像数据库中视图的味道</span>。在数据库中的视图对n个表的组合，客户端程序通过访问数据库的视图，而不必直接访问表，这样就减少了sql语句的编写，也可以减少很多代码量。如果数据的表万一有所改动，一般修改对应的视图就行了，如果要修改客户端程序，工作也不会很大。数据库的表之间的关系越复杂，越能体现这一点。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而在一个软件系统中，一个子系统（含有n&gt;=1的个类）可能会有m个用户类调用，在最坏的情况下，如果这n个类的接口都要修改一下，那么就会有n+m的修改工作量。<span style="color: #ff0000;">例如，在现实的软件开发中，如果需求变更，或者起先的设计错误，需要对代码进行修改，又恰恰碰到这种代码结构，如果应用了facade外观模式，修改的工作量将会大大的减少。例如：<span style="color: #0000ff;">spring的示范例子jpetstore里面的org.springframework.samples.jpetstore.domain.logic.PetStoreFacade，ejb3的petstore里面的PetStoreService,PetStoreApplication等，就是一些典型的例子。</span><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; facade外观模式的代码框架：</p>
<pre name="code" class="java">public class MyClass1{
   public void func(){}
}
public class MyClass2{
   public void func(){}
}
public class Facade{
   public void func(){
        MyClass1 obj1 = new MyClass1();
        obj1.func();
        MyClass2 obj2 = new MyClass2();
        obj2.func();
   }
}
public class Client{
   public static void main(String args[]){
        Facade facade = new Facade();
        facade.func();
   }
}</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/196613#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Sun, 25 May 2008 00:36:50 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/196613</link>
        <guid>http://linbzh.javaeye.com/blog/196613</guid>
      </item>
      <item>
        <title>flyweight享元模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/196289" style="color:red;">http://linbzh.javaeye.com/blog/196289</a>&nbsp;
          发表时间: 2008年05月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flyweight享元模式是实现对象的共享，减少重复数据的存储，从而减少内存分配的开销。享元模式融合了工厂模式和单例模式的思想，实际上也可以说享元模式是特殊的工厂模式。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果要创建同个对象的n个实例，而通常这n个实例中的m个属性的值大部分或全部是相同的，那么最坏的情况就会有n*m个相同的数据占据了不同的内存空间，如果n*m的值较大的话，就可以考虑flyweight享元模式了。<span style="color: #ff0000;">享元模式就把这m个相同的属性提取出来，结合单例模式和工厂模式，来实现相同属性值的实例分配到同一块内存空间</span>（这样就只占用了1*m个内存空间了）。这m个属性通常叫内在信息，而其他会动态变化的信息叫外部信息。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 享元模式的基本架构：</p>
<pre name="code" class="java">public interface FlyweightIntr {//接口
  public String get();
}
public class FlyweightFactory {//享元工厂
  private HashMap lstFlyweight;
  private static FlyweightFactory factory = new FlyweightFactory();
  private FlyweightFactory() {
    lstFlyweight = new HashMap();
  }
  public synchronized FlyweightIntr getFlyweight(String str) {//根据str获取FlyweightIntr实例
    if (lstFlyweight.get(str) == null) {//如果不存在，则新建
      FlyweightIntr fw = new Flyweight(str);
      lstFlyweight.put(str, fw);
      return fw;
    } else {//如果已经记录了，则获取
      return (FlyweightIntr) lstFlyweight.get(str);
    }
  }
  public static FlyweightFactory getInstance() {//享元工厂
    return factory;
  }
  private class Flyweight implements FlyweightIntr {
    private String str;
    private Flyweight(String str) {
      this.str = str;
    }
    private void set(String str) {
      this.str = str;
    }
    public String get() {
      return str;
    }
  }
public class MyClass {
  String myStr;
  FlyweightIntr obj;
  public MyClass(String myStr, FlyweightIntr fw) {
    this.myStr = myStr;
    obj = fw;
  }
  public void print() {
    System.out.println(myStr+"  "+obj.get());
  }
}
public class Main{
  public static void main(String args[]){
      FlyweightFactory factory = FlyweightFactory.getInstance();
      FlyweightIntr flyweight = factory.getFlyweight("1");
      MyClass myClass = new MyClass("a",flyweight);
      myClass.print();
      flyweight = factory.getFlyweight("1");
      myClass = new MyClass("b",flyweight);
      myClass.print();
      flyweight = factory.getFlyweight("2");
      myClass = new MyClass("c",flyweight);
      myClass.print();
      flyweight = factory.getFlyweight("2");
      myClass = new MyClass("d",flyweight);
      myClass.print();
  }
}</pre>
<p>&nbsp;&nbsp;<br /><span style="color: #ff0000;">利用享元模式的思想，进一步的演化，可以把一些不变的数据，放在外部文件作为模版，以便复用。</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/196289#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Sat, 24 May 2008 00:35:46 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/196289</link>
        <guid>http://linbzh.javaeye.com/blog/196289</guid>
      </item>
      <item>
        <title>composite合成模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/195277" style="color:red;">http://linbzh.javaeye.com/blog/195277</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; composite合成模式可以使用户对象以同样的方式对待单独的对象或复合的对象，合成模式要设计一个公共接口，即可提供给单独的对象使用，也可以供给复合对象使用。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使得用户类一致地使用单独的对象或者复合的对象，也不必关系要如何处理复合对象，只需要向复合对象添加单独对象即可。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; junit的Test接口的两个子类TestCase和TestSuite就是使用了合成模式。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其部分关键源代码如下，合成模式的代码结构基本上跟下面代码一样：</p>
<pre name="code" class="java">package junit.framework;
/** * A &lt;em&gt;Test&lt;/em&gt; can be run and collect its results. * * @see TestResult
 */
public interface Test {
 /**
  * Counts the number of test cases that will be run by this test.
  */
 public abstract int countTestCases();
 /**
  * Runs a test and collects its result in a TestResult instance.
  */
 public abstract void run(TestResult result);
}

package junit.framework;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public abstract class TestCase extends Assert implements Test {
 /*......*/
 public int countTestCases() {
  return 1;
 }
 public TestResult run() {
  TestResult result= createResult();
  run(result);
  return result;
 }
 /**
  * Runs the test case and collects the results in TestResult.
  */
 public void run(TestResult result) {
  result.run(this);
 }
 /*......*/
}
package junit.framework;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

public class TestSuite implements Test {
 /*......*/
 private Vector&lt;Test&gt; fTests= new Vector&lt;Test&gt;(10);
 /**
  * Adds a test to the suite.
  */
 public void addTest(Test test) {
  fTests.add(test);
 }
 /**
  * Adds the tests from the given class to the suite
  */
 public void addTestSuite(Class&lt;? extends TestCase&gt; testClass) {
  addTest(new TestSuite(testClass));
 }
 
 /**
  * Counts the number of test cases that will be run by this test.
  */
 public int countTestCases() {
  int count= 0;
  for (Test each : fTests)
   count+=  each.countTestCases();
  return count;
 }

 /**
  * Runs the tests and collects their result in a TestResult.
  */
 public void run(TestResult result) {
  for (Test each : fTests) {
     if (result.shouldStop() )
      break;
   runTest(each, result);
  }
 }
 
 public void runTest(Test test, TestResult result) {
  test.run(result);
 }
 /*......*/
}</pre>
<p>&nbsp;要一起执行若干个TestCase只要向TestSuit的addTest添加，和TestCast一样执行run即可。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/195277#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Wed, 21 May 2008 14:37:03 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/195277</link>
        <guid>http://linbzh.javaeye.com/blog/195277</guid>
      </item>
      <item>
        <title>bridge桥接模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/195248" style="color:red;">http://linbzh.javaeye.com/blog/195248</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bridge桥接模式的目的和decorator装饰器模式是一样的，都是避免过多的子类，只是它们的实现的方法有所不同，桥接模式采用聚合的方式来实现。要对类的功能进行扩展，可以修改现有的代码来做，但是如果一个父类的n个子类都要该功能，那么就得修改n次，不但工作量大而且重复代码量很多。这也违反了面向对象的开放/封闭原则（对扩展来说是开放的，对修改来说是封闭的）。在前面的《decorator装饰器模式》中提到的&ldquo;父类的n个子类的都要派生出子类并实现这些功能&rdquo;，这种方来处理但然也是不合理的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #888888;">bridge桥接模式中&ldquo;将抽象化与实现化脱偶，使得二者可以独立地变化&rdquo;的意思，就是利用聚合的方法对，在新类中对原接口进行封装，并实现特定的功能，用户只要向该新类传进原接口的一个子类的引用，对原接口对象进行实例化，用户就可以得到某些的应用。</span><span style="color: #ff0000;"><span style="color: #888888;">如果需要就对添加的类进行任何的改变，只要修改该新添加的类就行了。这就是独立地变化的体现。</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span><span style="color: #000000;">在decorator装饰器模式中，如果原父类的方法较多，那么Decorator继承过来的函数也就会很多。使用桥接模式就不存在这种情况。也就是说如果只想对目的类的某个或几个方法，用桥接模式就行了，代码量比较少。如果想像原类的一样使用新类，就用装饰器模式，但是可能会带来不必要的麻烦。<br />
<pre name="code" class="java">public interface Info{      
   public String read();      
   public void save();      
   public void setStr(String str);      
   public String getStr();      
}      
public class FileInfo implements Info{      
   protect String str;      
   public void read(){/*...*/}      
   public void save(){/*...*/}      
   public void setStr(String str){this.str=str;}      
   public String getStr(){return str;}      
}      
public class NetInfo implements Info{      
   protect String str;      
   public void read(){/*...*/}      
   public void save(){/*...*/}      
   public void setStr(String str){this.str=str;}      
   public String getStr(){return str;}      
}      
public interface Bridge{      
   public void save();      
}      
public class XmlDocument implements Bridge{      
   private Info info;      
   public XmlDocument(Info info){this.info = info;}      
   public void save(){xml();info.save();}      
   public void xml(){String str=info.read();/*对str进行处理...*/info.setStr(str);}      
}      
public class EncrypDocument implements Bridge{      
   private Info info;      
   public EncrypDocument(Info info){this.info = info;}      
   public void save(){encryp();info.save();}      
   public void encryp(){String str=info.read();/*对str进行处理...*/info.setStr(str);}   

   
}      
public class Main{      
   public static void main(String args[]){      
      Info info = new NetInfo();      
      Bridge b = new XmlDocument(info);      
      b.save();      
   }      
} </pre>
<font><font color="#000000">
<p>&nbsp;</p>
</font></font></span><font>
<p>&nbsp;</p>
</font></span></p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/195248#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Wed, 21 May 2008 14:06:45 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/195248</link>
        <guid>http://linbzh.javaeye.com/blog/195248</guid>
      </item>
      <item>
        <title>decorator装饰器模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/195064" style="color:red;">http://linbzh.javaeye.com/blog/195064</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; decorator装饰器模式，动态地扩展一个对象的功能，而不需要改变原始的类代码或使用继承。是通过创建一个跟目的类同一等级（继承目的类的父类）的称为装饰器的封装对象来实现的。要新添加的功能类继承这个装饰器，这样用户类可以像使用原来的类那样使用新添加的功能类。<br />&nbsp;&nbsp;&nbsp; decorator装饰器模式可以动态地添加功能，也可以动态地撤销功能。如果一个父类的n个子类，都需要有一个或若干个功能，而它们操作该功能的代码结构基本一致，这个时候就可以考虑使用decorator装饰器模式。如使用继承来实现的话，父类的n个子类的都要派生出子类并实现这些功能，随着子类的增加，重复的代码量会不断增加，灵活性较差。并且利用decorator装饰器模式易于添加任何功能的组合，同一个功能甚至可以添加两次，而继承难以做到这一点。</p>
<p>&nbsp;&nbsp;&nbsp;<span style="color: #888888;"> java中对流的操作，需要叠合多个对象，其实就是应用了装饰器模式。<br /></span>&nbsp;&nbsp;&nbsp; 例如，需要对不同类型的信息进行不同的储存方式，而不同信息的来源不同，这时可以考虑decorator装饰器模式。<br />public interface Info{<br />&nbsp;&nbsp; public void read(String path);<br />&nbsp;&nbsp; public void save();<br />}<br />public class FileInfo implements Info{<br />&nbsp;&nbsp; protect String str;<br />&nbsp;&nbsp; public void read(String path){/*...*/}<br />&nbsp;&nbsp; public void save(){/*...*/}<br />}<br />public class NetInfo implements Info{<br />&nbsp;&nbsp; protect String str;<br />&nbsp;&nbsp; public void read(String path){/*...*/}<br />&nbsp;&nbsp; public void save(){/*...*/}<br />}<br />public class Decorator impletments Info{<br />&nbsp;&nbsp; Info info;<br />&nbsp;&nbsp; protect String str;<br />&nbsp;&nbsp; public Decorator(Info info){this.info=info;}<br />&nbsp;&nbsp; public void read(String path){info.read(path);}<br />&nbsp;&nbsp; public void save(){info.save();}<br />}<br />public class HtmlDocument extends Decorator{<br />&nbsp;&nbsp; public HtmlDocument(Info info){super(info);}<br />&nbsp;&nbsp; public void save(){html();info.save();}<br />&nbsp;&nbsp; public void html(){/*对str进行处理...*/}<br />}<br />public class EncrypDocument extends Decorator{<br />&nbsp;&nbsp; public EncrypDocument(Info info){super(info);}<br />&nbsp;&nbsp; public void save(){encryp();info.save();}<br />&nbsp;&nbsp; public void encryp(){/*对str进行处理...*/}<br />}</p>
<p>public class Main{<br />&nbsp;&nbsp; public static void main(String args[]){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Info info = new NetInfo();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Decorator d = new XmlDocument(info);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d.read();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d.save();<br />&nbsp;&nbsp; }<br />}</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/195064#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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>Wed, 21 May 2008 00:45:27 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/195064</link>
        <guid>http://linbzh.javaeye.com/blog/195064</guid>
      </item>
      <item>
        <title>adapter适配器模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/194694" style="color:red;">http://linbzh.javaeye.com/blog/194694</a>&nbsp;
          发表时间: 2008年05月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; adapter适配器模式，目的在于扩展。是在原系统上进行扩展时用到的方法。<br />&nbsp;&nbsp;&nbsp; adapter适配器模式，个人认为在其名前加两个字，命名为接口适配模式。其用意是在保留原有类的前提下（即不改变原来的代码）把一个类的接口转换另一个接口，这样可以让具有不同接口的（原本接口不匹配的）多个类可以一起工作。而如果没有这样的转换，将不能使用到新的类提供的服务。<br />&nbsp;&nbsp;&nbsp; 适配器可分为类适配器和对象适配器。</p>
<p>&nbsp;&nbsp;&nbsp; 两种方式都实现了原接口或继承了原抽象类；在对新类的方法的重写的方式上，它们采用的方法不同，类适配器只要覆盖就行了，而对象适配则要过封装。<br />&nbsp;&nbsp;&nbsp; <span style="color: #ff0000;">在一个软件系统中，有时候使用了大量的接口，例如一个javaEE系统，DAO实现类要实现DAO接口，其中一个原因是为了扩展作准备的。</span></p>
<p>===============类适配器===============</p>
<pre name="code" class="java">public interface MyInterface{//原接口
  public boolean func(String str);
}
public class Object implements MyInterface{//原接口的实现类
  public boolean func(String str){/*...*/}
}
public class NewObject {//新类
  public boolean myfunc(String str){/*...*/}
}

public class NewChild extends NewObject{//新类的子类

}
public class Adapter extends NewObject  implements MyInterface{//适配器，被设计为新类的子类
  public boolean func(String str){
    return myfunc(str);
  }
}</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类适配器基于继承的概念，适配器被设计为新类的一个子类的形式；类适配器是通过接口方式进行适配；适配器类在内部调用它继承来的一个新类的方法；只能于对新类的方法进行适配，不能用于对新类的子类进行适配，这是因为适配器在创建的时候就已经与新类静态地联系在一起了；<span style="color: #ff0000;">由于继承的原故用户对象将能够知道新类的方法某些信息</span>。<br />===============对象适配器===============</p>
<pre name="code" class="java">public abstract calss MyAbstract{//抽象类
  public boolean func(String str);
}
class Object extends MyAbstract{//抽象类的子类
  public boolean func(String str){/*...*/}
}
class NewObject {//新类
  public boolean myfunc(String str){/*...*/}
}
public class Adapter extends MyAbstract{//适配器，可以适配新类的若干个子类
  private NewObject obj;
  public void setObj(NewObject obj){this.obj=obj;}
  public boolean func(String str){
    if(this.obj==null)return false;
    return obj.myfunc(str);
  }
}</pre>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对象适配使用对象组合的思想，它拥有新对象的一个引用。对于对象适配器，原接口或者原抽象类都是适应的；要对新类的子类进行适配也是适应的；对象适配器将通过它拥有的新实例的引用调用一个合适的新方法；<span style="color: #ff0000;">由于组合的原故</span><span style="color: #ff0000;">用户对象与新类是完全隔绝的，只有适配器知道新类的接口</span>；可以适配新类的若干个子类。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/194694#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 20 May 2008 01:46:50 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/194694</link>
        <guid>http://linbzh.javaeye.com/blog/194694</guid>
      </item>
      <item>
        <title>prototype原型模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/194524" style="color:red;">http://linbzh.javaeye.com/blog/194524</a>&nbsp;
          发表时间: 2008年05月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; prototype原型模式，简单明了的讲是，克隆并复用原型对象模式。<br />&nbsp;&nbsp;&nbsp; 当客户机需要创建对象集时，其中对象是相似的，或仅在状态方面有所不同，并且创建此类对象将花费很多的时间，所涉及的处理也较多。比如，通过复制具有类似结构代码，并进行修改，来创建一个新的实例，这时可以考虑采用原型模式，这样就不必通过复制修改代码来实现新的实例，只要克隆一下另一个实例，通过修改相应的属性的值来到达你的目的。<br />&nbsp;&nbsp;&nbsp; 克隆有浅克隆和深克隆。</p>
<pre name="code" class="java">class Person implements Cloneable {
  private String name;
  public String getName() {
    return name;
  }
  public void setName(String s) {
    name = s;
  }
  public Person(String s) {
    name = s;
  }
  public Object clone() {
    Person p = new Person(name);//深克隆
    return p;
    /*try {//浅克隆
      return super.clone();
    } catch (CloneNotSupportedException e) {
      return null;
    }*/
  }
}
public class CopyTest {
  public static void main(String[] args) {
    Person p = new Person("A");
    System.out.println(p.getName());
    Person q = (Person) p.clone();
    System.out.println(q.getName());
    q.setName("B");
    System.out.println(q.getName());
    System.out.println(p.getName());
  }
}</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/194524#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 19 May 2008 17:38:27 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/194524</link>
        <guid>http://linbzh.javaeye.com/blog/194524</guid>
      </item>
      <item>
        <title>builder构造模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/194436" style="color:red;">http://linbzh.javaeye.com/blog/194436</a>&nbsp;
          发表时间: 2008年05月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp; builder构造模式，简单明了的讲就是一个对象（或者说是一个部件）实例化过程的提取模式。目的在于方便维护和扩展。<br />&nbsp;&nbsp; 如果要创建的对象是复杂的，而且组成对象创建工程的一系列步骤可以按不同的方式来生成不同的对象，这是就应该要考虑使用构造模式，否则你把构造的所有的过程都放在一个对象里面，代码可能会变得很臃肿，这时应该把系统模块化。允许创建复杂的对象，可以只提供要创建的对象类型的相关信息，并且使有关对象创建的详细信息对客户机保持透明，这种方式方式允许相同的过程生成不同的对象。<br />&nbsp;&nbsp; 在jdon里面讲的设计模式之Builder的例子(<a href="http://www.jdon.com/designpatterns/builder.htm">http://www.jdon.com/designpatterns/builder.htm</a>)不算经典，本人看过的最好的例子是Partha Kuchana的《Software Architecture Design Patterns in JAVA》中的一个有关在线任务站点的例子。Partha Kuchana的例子更能体现builder构造模式的优点。<br />&nbsp;&nbsp; 很多人认为工厂模式和构造模式有类似的方法（jdon的板桥里人也这样认为），也容易被这两个模式混淆，但是我认为其实不然，更确切的说应该是构造模式融合了工厂模式的思想。只是构造模式把工厂模式的应用在不同的场合，但是在构造模式中融合的工厂模式和原本的工厂模式本质上是一致的。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/194436#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 19 May 2008 14:27:57 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/194436</link>
        <guid>http://linbzh.javaeye.com/blog/194436</guid>
      </item>
      <item>
        <title>singleton模式</title>
        <author>linbzh</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://linbzh.javaeye.com">linbzh</a>&nbsp;
          链接：<a href="http://linbzh.javaeye.com/blog/194208" style="color:red;">http://linbzh.javaeye.com/blog/194208</a>&nbsp;
          发表时间: 2008年05月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; singleton单例设计模式，目的在于类之间的信息共享。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; singleton单例设计模式也是相当容易理解的模式之一。就是在整个系统中，只有一个实例。更确切的讲，应该是让jvm一旦为某对象创建了一个引用，就不会在创建的一种模式。举一个在本人的项目中比较典型的例子，就是用户在某个类中就行了一些信息处理，接着用户可能会频繁的使用到这些处理后的信息而且这些信息占用的空间较小，那么就应该把这些信息保存在一个单例中。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; singleton单例设计模式代码基本都是这样:</p>
<pre name="code" class="java">public class Singleton{
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstall(){
    if(singleton==null)singleton=new singleton();
    return singleton;
} </pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在构建b/s架构的应用时，要小心使用，因为创建一个单例是在web服务器的容器共享的，任何用户都可以用，如果是单用户使用，只能放到session里面了(web服务器的servlet进程为每个用户开启了一个线程)。</p>
          <br/>
          <span style="color:red;">
            <a href="http://linbzh.javaeye.com/blog/194208#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></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, 19 May 2008 01:37:50 +0800</pubDate>
        <link>http://linbzh.javaeye.com/blog/194208</link>
        <guid>http://linbzh.javaeye.com/blog/194208</guid>
      </item>
  </channel>
</rss>