<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>ZhengJian</title>
    <description>要腾云驾雾，在暴风雨中成长</description>
    <link>http://luchar.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>Java设计模式之代理模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/180892" style="color:red;">http://luchar.javaeye.com/blog/180892</a>&nbsp;
          发表时间: 2008年04月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>      <span id="vrga"><strong id="jr51">一、定义</strong>
</span>
<br id="v6yx" />
&nbsp;&nbsp;&nbsp;&nbsp; 代理模式（Proxy Pattern）, 为其他对象提供一种代理以控制对这个对象的访问。<span style="font-size: x-small;"><span id="ua25"><span style="font-size: x-small;">在某些情况下</span>
，一个客户不</span>
</span>
想或者不能直接引用另一个对象，而代理对象可以在客户端和目标对象之间起到中介的作用。</p>
<p class="MsoNormal" id="hvio">&nbsp;&nbsp;&nbsp;&nbsp; 代理模式一般涉及到的角色有：</p>
<p class="MsoNormal" id="m5u8">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span id="yk.c"><strong id="kvob">抽象角色</strong>
</span>
：声明真实对象和代理对象的共同接口；</p>
<p class="MsoNormal" id="sgjc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span id="zira"><strong id="x1_p">代理角色</strong>
</span>
：
代理对象角色内部含有对真实对象的引用，从而可以操作真实对象，同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时，代理对象可
以在执行真实对象操作时，附加其他&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 的操作，相当于对真实对象进行封装。</p>
<p class="MsoNormal" id="aanr">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span id="mils"><strong id="kucj">真实角色</strong>
</span>
：代理角色所代表的真实对象，是我们最终要引用的对象。</p>
<div id="l8xd" style="padding: 1em 0pt; text-align: left;"><img src="http://docs.google.com/File?id=df2ff8cn_264fxmm9jgk_b" id="mmkb" alt="" style="width: 364px; height: 273px;" />
</div>
<p>二、<strong id="u7j_">为什么要使用Proxy模式<br id="n36-" />
</strong>
 1.授权机制
不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用
户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户&nbsp;&nbsp; 对论坛的访问权限.
                  </p>
<p id="hu8:">2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.<br id="hr5q" />
&nbsp; 举例两个具体情况: <br id="i3rf" />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1)如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很
迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 替真正的图片.<br id="nw22" />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2)如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象.<br id="qmzu" />
                  </p>
<p id="dvqn">&nbsp; 总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存。Proxy应用范围很广,现在流行的分布计算方式RMI和Corba等都是Proxy模式的应用。</p>
<p><br id="r_l." />
<strong id="u7j_">三、</strong>
<strong id="u6:j">如何使用<br id="bz64" />
</strong>
</p>
<p class="MsoNormal" id="i1ib">以下以《Java与模式》中的示例为例：</p>
<p class="MsoNormal" id="ky78"><strong id="j1gq">抽象角色：</strong>
</p>
<p class="MsoNormal" id="t2gy">abstract public class Subject{</p>
<p class="MsoNormal" id="mtw1">&nbsp;&nbsp;&nbsp; abstract public void request();</p>
<p class="MsoNormal" id="ffz0">}</p>
<p class="MsoNormal" id="xagi"><span id="o9.y"><strong id="kqmg">真实角色：</strong>
</span>
实现了Subject的request()方法。</p>
<p class="MsoNormal" id="l6uj">public class RealSubject extends Subject{<br id="gyef" />
</p>
<p class="MsoNormal" id="unz0">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public RealSubject(){</p>
<p class="MsoNormal" id="j.jo">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p class="MsoNormal" id="i-2g">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void request(){<br id="k_ka" />
 </p>
<p class="MsoNormal" id="zj_m">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&quot;From real subject.&quot;);</p>
<p class="MsoNormal" id="hqz.">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="MsoNormal" id="s:a0">}</p>
<p class="MsoNormal" id="ftn."><strong id="z9b3">代理角色：</strong>
</p>
<p class="MsoNormal" id="w90.">public class ProxySubject extends Subject{</p>
<p class="MsoNormal" id="e8l-">&nbsp;&nbsp;&nbsp; private RealSubject realSubject;&nbsp; //以真实角色作为代理角色的属性</p>
<p class="MsoNormal" id="s66f">&nbsp;</p>
<p class="MsoNormal" id="mfi9">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public ProxySubject(){</p>
<p class="MsoNormal" id="jnc4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="MsoNormal" id="d0sf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //该方法封装了真实对象的request方法</p>
<p class="MsoNormal" id="vgw7">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void request()&nbsp; {</p>
<p class="MsoNormal" id="oqpw">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;preRequest();&nbsp; </p>
<p class="MsoNormal" id="r2bh">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;if( realSubject == null ){</p>
<p class="MsoNormal" id="jeb1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; realSubject = new RealSubject();</p>
<p class="MsoNormal" id="p8sf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="MsoNormal" id="zqt4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">realSubject.request();&nbsp;</span>
 //此处执行真实对象的request方法</p>
<p class="MsoNormal" id="rn4c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;postRequest(); </p>
<p class="MsoNormal" id="ukbs">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="MsoNormal" id="kruw">&nbsp;&nbsp;&nbsp; private void preRequest(){</p>
<p class="MsoNormal" id="mr72">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //something you want to do before requesting</p>
<p class="MsoNormal" id="i_bn">&nbsp;&nbsp;&nbsp; }</p>
<p class="MsoNormal" id="e99d">&nbsp;&nbsp;&nbsp; private void postRequest() {</p>
<p class="MsoNormal" id="j36g">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //something you want to do after requesting</p>
<p class="MsoNormal" id="gf9q">&nbsp;&nbsp;&nbsp; }</p>
<p class="MsoNormal" id="gkvt">}</p>
<p class="MsoNormal" id="p8ik">客户端调用：</p>
<p class="MsoNormal" id="jdjc">Subject sub=new ProxySubject();</p>
<p class="MsoNormal" id="hdu.">Sub.request();</p>
<p class="MsoNormal" id="yhb5">&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff0000;">由
以上代码可以看出，客户实际需要调用的是RealSubject类的request()方法，现在用ProxySubject来代理
RealSubject类，同样达到目的，同时还封装了其他方法(preRequest(),postRequest())，可以处理一些其他问题。</span>
</p>
<p class="MsoNormal" id="rrpk"><span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;
另外，如果要按照上述的方法使用代理模式，那么真实角色必须是事先已经存在的，并将其作为代理对象的内部属性。但是实际使用时，一个真实角色必须对应一个
代理角色，如果大量使用会导致类的急剧膨胀；此外，如果事先并不知道真实角色，该如何使用代理呢？这个问题可以通过Java的动态代理类来解决。</span>
</p>
<p class="MsoNormal" id="jrl2">&nbsp;</p>
<p class="MsoNormal" id="qmmr"><strong id="pl.5">四、动态代理类</strong>
</p>
<p class="MsoNormal" id="q_jr">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java动态代理类位于Java.lang.reflect包下，一般主要涉及到以下两个类：</p>
<p class="MsoNormal" id="o4bd">(1). Interface InvocationHandler：该接口中仅定义了一个方法Object：invoke(Object obj,Method method, <a id="k7da">Object</a>
[]&nbsp;args)。在实际使用时，第一个参数obj一般是指代理类，method是被代理的方法，如上例中的request()，args为该方法的参数数组。这个抽象方法在代理类中动态实现。</p>
<p class="MsoNormal" id="r_wu"><br id="tynt" />
(2).Proxy：该类即为动态代理类，作用类似于上例中的ProxySubject，其中主要包含以下内容：</p>
<p class="MsoNormal" id="szvc">Protected Proxy(InvocationHandler h)：构造函数，估计用于给内部的h赋值。</p>
<p class="MsoNormal" id="v2n0">Static Class getProxyClass (ClassLoader&nbsp;loader, Class[]&nbsp;interfaces)：获得一个代理类，其中loader是类装载器，interfaces是真实类所拥有的全部接口的数组。</p>
<p class="MsoNormal" id="opc2">Static Object <a id="rzl6">newProxyInstance</a>
(ClassLoader&nbsp;loader, Class[]&nbsp;interfaces, InvocationHandler&nbsp;h)：返回代理类的一个实例，返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。<br id="y5r." />
</p>
<p class="MsoNormal" id="xi2."><br id="ezbq" />
&nbsp;&nbsp; &nbsp; 所谓Dynamic
Proxy是这样一种class：它是在运行时生成的class，在生成它时你必须提供一组interface给它，然后该class就宣称它实现了这些
interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦，这个Dynamic
Proxy其实就是一个Proxy，它不会替你作实质性的工作，在生成它的实例时你必须提供一个handler，由它接管实际的工作。</p>
<p class="MsoNormal" id="j37o">&nbsp;&nbsp;&nbsp; 在使用动态代理类时，我们必须实现InvocationHandler接口，以第一节中的示例为例：</p>
<p class="MsoNormal" id="i64b">抽象角色(之前是抽象类，此处应改为接口)：</p>
<p class="MsoNormal" id="pr4.">public interface Subject{</p>
<p class="MsoNormal" id="tsyb">&nbsp;&nbsp;&nbsp; abstract public void request();</p>
<p class="MsoNormal" id="zjj1">}</p>
<p class="MsoNormal" id="xi6j">具体角色RealSubject：同上；</p>
<p class="MsoNormal" id="lxra">&nbsp;</p>
<p class="MsoNormal" id="hq3i">代理角色：</p>
<p class="MsoNormal" id="uo14">import java.lang.reflect.Method;</p>
<p class="MsoNormal" id="io1r">import java.lang.reflect.InvocationHandler;</p>
<p class="MsoNormal" id="yses">public class DynamicSubject implements InvocationHandler {</p>
<p class="MsoNormal" id="l.iw">&nbsp; private Object sub;</p>
<p class="MsoNormal" id="ybio">&nbsp; public DynamicSubject() {</p>
<p class="MsoNormal" id="on4w">&nbsp; }</p>
<p class="MsoNormal" id="xmm5">&nbsp; public DynamicSubject(Object obj) {</p>
<p class="MsoNormal" id="tzwh">&nbsp;&nbsp;&nbsp; sub = obj;</p>
<p class="MsoNormal" id="s0lv">&nbsp; }</p>
<p class="MsoNormal" id="wf:-">&nbsp; public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {</p>
<p class="MsoNormal" id="els6">&nbsp;&nbsp;&nbsp; System.out.println(&quot;before calling &quot; + method);</p>
<p class="MsoNormal" id="b8fr">&nbsp;&nbsp;&nbsp; method.invoke(sub,args);</p>
<p class="MsoNormal" id="j7me">&nbsp;&nbsp;&nbsp; System.out.println(&quot;after calling &quot; + method);</p>
<p class="MsoNormal" id="p:l7">&nbsp;&nbsp;&nbsp; return null;</p>
<p class="MsoNormal" id="pct1">&nbsp; }</p>
<p class="MsoNormal" id="wo7j">}</p>
<p class="MsoNormal" id="g_wq">&nbsp;</p>
<p class="MsoNormal" id="na03">&nbsp;&nbsp;&nbsp;&nbsp;
该代理类的内部属性为Object类，实际使用时通过该类的构造函数DynamicSubject(Object
obj)对其赋值；此外，在该类还实现了invoke方法，该方法中的method.invoke(sub,args);其实就是调用被代理对象的将要被
执行的方法，方法参数sub是实际的被代理对象，args为执行被代理对象相应操作所需的参数。通过动态代理类，我们可以在调用之前或之后执行一些相关操
作。</p>
<p class="MsoNormal" id="c9a4">客户端：</p>
<p class="MsoNormal" id="s3n-">import java.lang.reflect.InvocationHandler;</p>
<p class="MsoNormal" id="xl5g">import java.lang.reflect.Proxy;</p>
<p class="MsoNormal" id="csx2">import java.lang.reflect.Constructor;</p>
<p class="MsoNormal" id="c-mv">import java.lang.reflect.Method;</p>
<p class="MsoNormal" id="pn9:">&nbsp;</p>
<p class="MsoNormal" id="pi1y">public class Client{</p>
<p class="MsoNormal" id="hpl9">&nbsp;</p>
<p class="MsoNormal" id="sra2">&nbsp;&nbsp;&nbsp; static public void main(String[] args) throws Throwable{</p>
<p class="MsoNormal" id="ks_3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RealSubject rs = new RealSubject();&nbsp; //在这里指定被代理类</p>
<p class="MsoNormal" id="yqc1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InvocationHandler ds = new DynamicSubject(rs);&nbsp; //初始化代理类</p>
<p class="MsoNormal" id="qqgu">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Class cls = rs.getClass();</p>
<p class="MsoNormal" id="er8x">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //以下是分解步骤</p>
<p class="MsoNormal" id="tf7d">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</p>
<p class="MsoNormal" id="cmjf">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;</p>
<p class="MsoNormal" id="v:.v">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});</p>
<p class="MsoNormal" id="o_nd">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Subject subject =(Subject) ct.newInstance(new Object[]{ds});</p>
<p class="MsoNormal" id="jkf9">&nbsp;&nbsp;&nbsp;&nbsp; */</p>
<p class="MsoNormal" id="vaf4">&nbsp;&nbsp;&nbsp;&nbsp; //以下是一次性生成</p>
<p class="MsoNormal" id="quwz">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds );<br id="q2qo" />
</p>
<p class="MsoNormal" id="qffa"><br id="v.c0" />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subject.request();</p>
<p class="MsoNormal" id="n8hq">}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 通过这种方式，被代理的对象(RealSubject)可以在运行时动态改变，需要控制的接口(Subject接口)可以在运行时改变，控制的方式(DynamicSubject类)也可以动态改变，从而实现了非常灵活的动态代理关系。<br id="tpiz" />
<br id="tk34" />
<span id="g_cy"><strong id="p-d-">五、代理模式的应用</strong>
</span>
<br id="nker" />
一般来说分为几种：<br id="nai6" />
1、远程（Remote）代理：也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。<br id="fuph" />
2、虚拟（Virtual）代理：根据需要将一个资源消耗很大或者比较复杂的对象延迟的真正需要时才创建。<br id="w4md" />
&nbsp;&nbsp;&nbsp; 比如说你打开一个很大的HTML网页时，里面可能有很多的文字和图片，但你还是可以很快的打开它，此时你所看到的是所有的文字，但图片却是一张张的下载后才能看到。那些未打开的图片框，就是通过虚拟代理来代替了真实的图片，此时代理存储了真实图片的路径和尺寸。<br id="acr1" />
3、保护（Protect or Access）代理：控制对一个对象的访问权限。一般用于对象有 不同权限的时候。<br id="qyx6" />
4、智能引用（Smart Reference）代理：当调用真实对象时，代理出来另外一些事，提供比对目标对象额外的服务。<br id="og-k" />
&nbsp;&nbsp;&nbsp; 如：计算真实对象的引用次数，这样当该对象没有引用时，可以自动释放它；或当第一次引用一个持久对象时，将它装入内存；或在访问一个实际对象前，检查是否已经锁定它，以确保其它对象不能改变它。它们都是通过代理在访问一个对象时附加一些内务处理。<br id="p.ez" />
<br id="qrmh" />
</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/180892#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><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><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 09 Apr 2008 16:36:17 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/180892</link>
        <guid>http://luchar.javaeye.com/blog/180892</guid>
      </item>
      <item>
        <title>Java设计模式之适配器模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/180878" style="color:red;">http://luchar.javaeye.com/blog/180878</a>&nbsp;
          发表时间: 2008年04月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;</p>
<p id="n_ks"><span id="j_yd"><strong id="vf:2">一、适配器模式定义</strong>
</span>
<br id="m563" />
&nbsp;&nbsp;&nbsp;&nbsp; Adapter，将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。</p>
<p id="f351"><br id="naaf" />
</p>
<p id="f351"><span id="vx4m"><strong id="shhb">二、详细说明</strong>
</span>
<br id="ini9" />
&nbsp;&nbsp;&nbsp;&nbsp; 通常，客户类（clients&nbsp;of&nbsp;class）通过类的接口访问它提供的服务。有时，现有的类（existing&nbsp;class）可以提供客户类的功能
需要，但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口太详细或者缺乏详细或接口的名称与客户类所查找的不同等诸多不同原因导致的。<br id="e8i8" />
<br id="v5au" />
　
　在这种情况下，现有的接口需要转化（convert）为客户类期望的接口，这样保证了对现有类的重用。如果不进行这样的转化，客户类就不能利用现有类所
提供的功能。适配器模式（Adapter&nbsp;Pattern）可以完成这样的转化。适配器模式建议定义一个包装类，包装有不兼容接口的对象。这个包装类指的
就是适配器（Adapter），它包装的对象就是适配者(Adaptee)。适配器提供客户类需要的接口，适配器接口的实现是把客户类的请求转化为对适配
者的相应接口的调用。换句话说：当客户类调用适配器的方法时，在适配器类的内部调用适配者类的方法，这个过程对客户类是透明的，客户类并不直接访问适配者
类。因此，适配器可以使由于借口不兼容而不能交互的类可以一起工作（work&nbsp;together）。</p>
<p><br id="enm7" />
</p>
<p id="abhg"><strong id="z:5f">三、Adapter的分类</strong>
</p>
<p id="abhg">适配器总体上可以分为两类，类适配器（Class&nbsp;Adapter）和对象适配器(Object&nbsp;Adapter)</p>
<h4 id="mhqr"><span style="font-size: x-small;">类适配器：</span>
</h4>
<p>　　类适配器是通过继承类适配者类（Adaptee&nbsp;Class）实现的，另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候，适配器内部调用它所继承的适配者的方法。<br id="k8bg" />
</p>
&nbsp;&nbsp;&nbsp;
<h4 id="wnnn"><span style="font-size: x-small;">对象适配器：</span>
</h4>
<p>　　对象适配器包含一个适配器者的引用（reference），与类适配器相同，对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候，对象适配器调它所包含的适配器者实例的适当方法。<br id="duu0" />
<br id="hl5b" />
　　下表是类适配器（Class&nbsp;Adapter）和对象适配器(Object&nbsp;Adapter)的详细不同：<br id="dt48" />
<br id="rcku" />
</p>
<p id="p.1p" align="center"><img src="http://dev.yesky.com/imagelist/05/10/b6z1pomi30yn.bmp" id="v8ck" alt="" />
</p>
<p><br id="djd9" />
</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/180878#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><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 09 Apr 2008 16:04:44 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/180878</link>
        <guid>http://luchar.javaeye.com/blog/180878</guid>
      </item>
      <item>
        <title>Java设计模式之单例模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179625" style="color:red;">http://luchar.javaeye.com/blog/179625</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span style="font-weight: bold">一、概述</span><br />
&nbsp;&nbsp;&nbsp; 单例模式（Singleton），保证一个类仅有一个实例，并提供一个访问它的全局访问点。<br />
&nbsp;&nbsp;&nbsp; 通常我们可以让一个全局变量使得一个对象被访问，但它不能防止你实例化多个对象。一个最好的办法就是，让类自身负责保存它的唯一实例。这个类可以保证没有其它实例可以被创建，并且它可以提供一个访问该实例的方法。<br />
<br />
<span style="font-weight: bold">二、

一般Singleton模式通常有几种种形式</span><br />
<br />
<div id="p8e4" style="border-style: none solid none none; border-color: -moz-use-text-color #cccccc -moz-use-text-color -moz-use-text-color; border-width: medium 1pt medium medium; padding: 0cm 15pt 0cm 0cm; background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"><p id="bq3i" style="border: medium none ; padding: 0cm; background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"><span style="font-size: 10.5pt; font-family: 宋体; color: black"><span>
</span><span style="color: #ff0000">第一种形式</span><span>: </span>定义一个类，它的构造函数为<span>private</span>的，它有一个<span>static</span>的<span>private</span>的该类变量，在类初始化时实例话，通过一个<span>public</span>的<span>getInstance</span>方法获取对它的引用<span>,</span>继而调用其中的方法。</span></p><p id="bq3i" style="border: medium none ; padding: 0cm; background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"><span style="font-size: 10.5pt; font-family: 宋体; color: black"><span><br /></span></span></p><pre name="code" class="java">public class Singleton {
private Singleton(){}
　　    //在自己内部定义自己一个实例，是不是很奇怪？
　　    //注意这是private 只供内部调用
　　    private static Singleton instance = new Singleton();
　　    //这里提供了一个供外部访问本class的静态方法，可以直接访问　　
　　    public static Singleton getInstance() {
　　　　    return instance; 　　
　　    }
} </pre><p id="bq3i" style="border: medium none ; padding: 0cm; background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"><span style="font-size: 10.5pt; font-family: 宋体; color: black"><span><br /></span></span></p>

<p id="bq3i" style="border: medium none ; padding: 0cm; background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"><span style="font-size: 10.5pt; font-family: 宋体; color: black"><span style="color: #ff0000">第二种形式</span><span>: <br /></span></span></p><pre name="code" class="java">public class Singleton {
　　private static Singleton instance = null;
　　public static synchronized Singleton getInstance() {
　　    //这个方法比上面有所改进，不用每次都进行生成对象，只是第一次　　　 　
　　    //使用时生成实例，提高了效率！
　　    if (instance==null)
　　　　    instance＝new Singleton();
        return instance; 　　

    }
} </pre><p id="bq3i" style="border: medium none ; padding: 0cm; background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"><br /><span style="font-size: 10.5pt; font-family: 宋体; color: black"><span>
</span><span style="color: #ff0000">其他形式</span><span>:<br />
</span>定义一个类，它的构造函数为<span>private</span>的，所有方法为<span>static</span>的。<span><br />
</span><span style="color: #ff0000">一般认为第一种形式要更加安全些</span> <span></span></span></p>


</div>


      
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179625#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</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>Sat, 05 Apr 2008 10:51:45 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179625</link>
        <guid>http://luchar.javaeye.com/blog/179625</guid>
      </item>
      <item>
        <title>Java设计模式之原型模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179624" style="color:red;">http://luchar.javaeye.com/blog/179624</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p id="n_ks"><span><strong>一、原型模式定义</strong></span><br />&nbsp;&nbsp;&nbsp;&nbsp;
                  用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.</p>
                  <p id="rm_y">&nbsp;&nbsp;&nbsp;&nbsp; Prototype模式允许一个对象再创建另外一个可定制的对象，根本无需知道任何如何创建的细节。</p><p id="rm_y">&nbsp;&nbsp;&nbsp;&nbsp; 工作原理是:通过将一个原型对象传给那个要发动创建的对象，这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。</p>
                  <p id="f351">&nbsp;</p><p id="f351"><span><strong>二、如何使用</strong></span><br />&nbsp;&nbsp;&nbsp;&nbsp;
                  因为Java中的提供<span style="color: #ff0000">clone()</span>方法来实现对象的克隆,所以Prototype模式实现一下子变得很简单.</p><br /><p id="abhg"><strong>三、实例</strong></p><pre name="code" class="java">public abstract class AbstractSpoon implements Cloneable{
　　String spoonName;

　　public void setSpoonName(String spoonName) {
            this.spoonName = spoonName;
      }
　　public String getSpoonName() {return this.spoonName;}

　　public Object clone(){
　　　　Object object = null;
　　　　try {
　　　　　　object = super.clone();
　　　　} catch (CloneNotSupportedException exception) {
　　　　　　System.err.println(&quot;AbstractSpoon is not Cloneable&quot;);
　　　　}
　　　　return object;
　　}
}</pre><p>&nbsp;有个具体实现(ConcretePrototype):</p><pre name="code" class="java">public class SoupSpoon extends AbstractSpoon{
　　public SoupSpoon(){
　　　　setSpoonName(&quot;Soup Spoon&quot;);
　　}
}</pre>&nbsp;<p id="dcyr">调用Prototype模式很简单:</p>
                  <p id="syir">AbstractSpoon spoon = new SoupSpoon();<br />
                  AbstractSpoon spoon2 = spoon.clone(); </p>
                  <p id="s1w1">当然也可以结合工厂模式来创建AbstractSpoon实例。</p>
                  <p id="t7yu"><span style="color: #ff0000">在Java中Prototype模式变成clone()方法的使用</span>，此方法执行的是该对象的&ldquo;浅表复制&rdquo;，而不&ldquo;深层复制&rdquo;操作。</p><br /><p id="t7yu"><span><strong>四、说明：
</strong></span><br /><span><strong>    克隆必须满足的条件：</strong></span>
<br />    a.对任何的对象x,都有：x.clone() != x,即克隆对象与原对象不是同一个对象。
<br />    b.对任何的对象x,都有：x.clone().getClass() == x.get getClass()，即克隆对象与原对象的类型是一样的。    c.如果对象x的equals()方法定义恰当的话，那么x.clone().equals(x)应当是成立的。
<br />    在java中实现clone()应该满足这三个条件。
<br />
<br /><span style="color: #ff0000"><span><strong>    浅复制</strong></span>：</span>复制了值类型对象，对于引用类型对象，只复制了引用，它指向原来引用的对象。Java中clone为浅复制。
<br /><span style="color: #ff0000"><span><strong>        深复制</strong></span>：</span>对值类型和引用类型的对象都生成一份新的拷贝. Java中可以通过串行化来进行深复制,前提是对象以及对象内部所引用的对象都是可串行化的，否则需要考虑将那些不可串行化的对象可否设为transient,排除&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在复制过程之外。
</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179624#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><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>Sat, 05 Apr 2008 10:49:19 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179624</link>
        <guid>http://luchar.javaeye.com/blog/179624</guid>
      </item>
      <item>
        <title>Java设计模式之构造者模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179619" style="color:red;">http://luchar.javaeye.com/blog/179619</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span><strong>一、概述</strong></span>&nbsp;<p class="MsoNormal"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; </span>&nbsp;

<span style="font-family: 宋体">构造者模式（</span><span>Builder Pattern</span><span style="font-family: 宋体">）：构造者模式将一个复杂对象的<span style="color: #ff0000">构造过程和它的表现层分离开来</span>，使得<span style="color: #ff0000">同样的构建过程可以创建不同的表示</span>，又称为生成器模式。</span></p><p class="MsoNormal"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 在软件系统</span> <span style="font-family: 宋体"><span style="font-family: 宋体">中，有时候面临着</span></span><span>&ldquo;<span style="font-family: 宋体">一个复杂对象</span></span><span>&rdquo;<span style="font-family: 宋体">的创建工作，其通常由各个部分的子对象用一定的算法构成；由于需求的变化，这个复杂对象的各个部分经常面临着剧烈的变</span></span>
<span style="font-family: 宋体"><span style="font-family: 宋体">化，但是将它们组合在一起的算法确相对稳定。如何应对这种变化？如何提供一种</span></span><span>&ldquo;<span style="font-family: 宋体">封装机制</span></span><span>&rdquo;<span style="font-family: 宋体">来隔离出</span></span><span>&ldquo;<span style="font-family: 宋体">复杂对象的各个部分</span></span><span>&rdquo;<span style="font-family: 宋体">的变化，从而保持系统中的</span></span><span>&ldquo;<span style="font-family: 宋体">稳定</span></span> <span style="font-family: 宋体"><span style="font-family: 宋体">构建算法</span></span><span>&rdquo;<span style="font-family: 宋体">不随着需求改变而改变？</span></span><span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">如果我们使用了构造者模式，那么</span></span><span style="font-family: 宋体"><span style="color: #ff0000">用户就只需要指定需要构造的类型就可以得到它们，而具体的构造过程和细节就不需要知道了。</span></span><span style="font-size: x-small"></span></p>

<p class="MsoNormal" style="font-weight: bold">&nbsp;</p><p class="MsoNormal" style="font-weight: bold">二、类图和图解</p><img id="n5wg" alt="" /><img id="s0wb" alt="" /><img src="http://docs.google.com/File?id=df2ff8cn_2589378k2cd" id="xnr9" alt="" style="width: 625px; height: 304px" /><img src="http://docs.google.com/File?id=df2ff8cn_2599cg9m7gp" id="xaaw" alt="" style="width: 553px; height: 323px" /><br /><br /><span><strong>三、构造者模式解析</strong></span><br />&nbsp;&nbsp;&nbsp; Builder：是为创建一个Product对象的各个部件指定的抽象接口<br />&nbsp;&nbsp;&nbsp; ConcreteBuilder：它是具体的构建者，实现Builder接口，构造和装配各个部件。<br />&nbsp;&nbsp;&nbsp; Product：具体的产品<br />&nbsp;&nbsp;&nbsp; Director：指挥者，它是构建一个使用Builder接口的对象。<br /><br />四、实例代码<pre name="code" class="java">//产品类：
package com.javapatterns.builder;

public class Product{
    public Product(){
       // System.out.println(&quot;product is initing.&quot;);
    }
}</pre>&nbsp;<pre name="code" class="java"> //抽象建造方法：
package com.javapatterns.builder;

abstract public class Builder{
    public abstract void buildPart1();

    public abstract void buildPart2();

    public abstract Product retrieveResult();
}</pre>&nbsp;<pre name="code" class="java">//具体的建造类：产品的零件制造
package com.javapatterns.builder;

public class ConcreteBuilder extends Builder{

    private Product product = new Product() ;
    public void buildPart1(){
        System.out.println(&quot;build part one.&quot;);
    }

    public void buildPart2(){
        System.out.println(&quot;build part two.&quot;);
    }

    public Product retrieveResult(){
        return product;
    }
}</pre>&nbsp;<pre name="code" class="java">//产品的建造过程：
package com.javapatterns.builder;

public class Director{
    private Builder builder;

    public Director(Builder builder){
        this.builder = builder;
    }

   public void construct(){
        builder = new ConcreteBuilder();

        builder.buildPart1();

        builder.buildPart2();

        builder.retrieveResult();

        //continue with other code
    }
}</pre>&nbsp;<pre name="code" class="java">//测试：
package com.javapatterns.builder;

public class Client{

    private static Director director;

    private static Builder builder = new ConcreteBuilder();
       
    public void requestBuild(){
       // director = new Director(builder);
    }
   
     public static void main(String[] args) {
        director = new Director(builder);
        director.construct();
    }

}</pre>&nbsp;<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179619#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</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, 05 Apr 2008 10:38:51 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179619</link>
        <guid>http://luchar.javaeye.com/blog/179619</guid>
      </item>
      <item>
        <title>Java设计模式之抽象工厂模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179617" style="color:red;">http://luchar.javaeye.com/blog/179617</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span style="font-family: 宋体">
<p id="h0h6"><strong>一 、抽象工厂模式（Abstract Factory）</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口，而无需指定它们具体的类。</p>
<p id="xsgh">&nbsp;</p></span>
<p id="xsgh"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;抽象工厂（Abstract Factory）模式，又称工具箱（Kit 或Toolkit）模式。</span></p>
<p id="n:qo">&nbsp;</p>
<p id="l4e1"><strong>二、创建过程如下</strong></p>
<p id="lgzc"><strong>&nbsp;&nbsp;&nbsp;&nbsp; </strong>一个具体工厂创建一个<span style="color: #ff0000">产品族</span>，<span style="color: #ff0000">一个产品族是不同系列产品的组合</span>，产品的创建的逻辑分在在每个具体工厂类中。所有的具体工厂继承自同一个抽象工厂。<br />&nbsp;&nbsp;&nbsp;&nbsp;客户端创建不同产品族的工厂，产品族的工厂创建具体的产品对客户端是不可见的。<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000">增加新的产品族时，需要增加具体工厂类</span>,符合OCP原则。<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000">增加新产品时，需要修改具体工厂类和增加产品类</span>，不符合OCP原则<br />&nbsp;&nbsp;&nbsp;&nbsp;如果没有应对&ldquo;多系列对象创建&rdquo;的需求变化，则没有必要使用抽象工厂模式，这时候使用简单的静态工厂完全可以。 </p>
<div id="xuks" align="left" style="padding: 1em 0px"><img src="http://docs.google.com/File?id=df2ff8cn_256gmxf8wd3" id="rrki" alt="" /></div>
<p id="ks13">&nbsp;</p>
<p id="dkh-">&nbsp;</p><p>
<strong>三、一个简单的实例</strong></p><pre name="code" class="java">// 产品 Plant接口
public interface IPlant { }
//具体产品PlantA，PlantB
public class PlantA implements IPlant {

　public PlantA () {
　　System.out.println(&quot;create PlantA !&quot;);
　}

　public void doSomething() {
　　System.out.println(&quot; PlantA do something ...&quot;);
　}
}
public class PlantB implements IPlant {
　public PlantB () {
　　System.out.println(&quot;create PlantB !&quot;);
　}

　public void doSomething() {
　　System.out.println(&quot; PlantB do something ...&quot;);
　}
}
// 产品 Fruit接口
public interface IFruit { }
//具体产品FruitA，FruitB
public class FruitA implements IFruit {
　public FruitA() {
　　System.out.println(&quot;create FruitA !&quot;);
　}
　public void doSomething() {
　　System.out.println(&quot; FruitA do something ...&quot;);
　}
}
public class FruitB implements IFruit {
　public FruitB() {
　　System.out.println(&quot;create FruitB !&quot;);
　}
　public void doSomething() {
　　System.out.println(&quot; FruitB do something ...&quot;);
　}
}
// 抽象工厂方法
public interface AbstractFactory {
　public IPlant createPlant();
　public IFruit createFruit() ;
}
//具体工厂方法
public class FactoryA implements AbstractFactory {
　public IPlant createPlant() {
　　return new PlantA();
　}
　public IFruit createFruit() {
　　return new FruitA();
　}
}
public class FactoryB implements AbstractFactory {
　public IPlant createPlant() {
　　return new PlantB();
　}
　public IFruit createFruit() {
　　return new FruitB();
　}
}</pre>&nbsp;<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179617#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><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>Sat, 05 Apr 2008 10:34:21 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179617</link>
        <guid>http://luchar.javaeye.com/blog/179617</guid>
      </item>
      <item>
        <title>Java设计模式之工厂方法模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179616" style="color:red;">http://luchar.javaeye.com/blog/179616</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p id="szq4"><strong>一 、工厂方法（Factory Method）模式</strong><br />&nbsp;&nbsp;&nbsp;&nbsp; 工厂方法模式的意义是<span style="color: #38761d">定义一个创建产品对象的工厂接口</span>，将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建，这样核心类成为一个抽象工厂角色，仅负责具体工厂子类必须实现的接口，这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。</p>
<p id="ktv1">&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: 宋体">工厂方法（Factory Method）模式，又称<span style="color: #ff0000">多态性工厂</span>（Polymorphic Factory）模<br />式或虚拟构造子（Virtual Constructor）模式；</span><br /><br /><strong>二、工厂方法模式角色与结构<br /></strong>&nbsp;&nbsp;&nbsp;&nbsp;抽象工厂（Creator）角色：是工厂方法模式的核心，与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。 <br />　 具体工厂（Concrete Creator）角色：这是实现抽象工厂接口的具体工厂类，包含与应用程序密切相关的逻辑，并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色：BulbCreator与TubeCreator。<br />　 抽象产品（Product）角色：工厂方法模式所创建的对象的超类型，也就是产品对象的共同父类或共同拥有的接口。在上图中，这个角色是Light。<br />　 具体产品（Concrete Product）角色：这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建，它们之间往往一一对应。</p>
<p id="y6:t"><strong><br /></strong><strong>三、创建过程如下</strong></p>
<p id="lgzc"><strong>&nbsp;&nbsp;&nbsp;&nbsp; </strong>一个工厂创建一个产品，所有的具体工厂继承自一个抽象工厂接口。<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000">客户端先创建不同产品的工厂，再由工厂创建具体产品</span>，产品的创建逻辑分散在每个具体工厂类中。<br />&nbsp;&nbsp;&nbsp;&nbsp;客户端只依赖于抽象工厂与抽象产品，不依赖任何具体的工厂与具体产品<br />&nbsp;&nbsp;&nbsp;&nbsp;增加新产品时，需要增加工厂类和产品类，符合OCP原则</p>
<p id="egux">&nbsp;</p><p>
<strong>四、一个简单的实例</strong>　　　</p><pre name="code" class="java">// 产品 Plant接口
public interface IPlant { }
//具体产品PlantA，PlantB
public class PlantA implements IPlant {

　public PlantA () {
　　System.out.println(&quot;create PlantA !&quot;);
　}

　public void doSomething() {
　　System.out.println(&quot; PlantA do something ...&quot;);
　}
}
public class PlantB implements IPlant {
　public PlantB () {
　　System.out.println(&quot;create PlantB !&quot;);
　}

　public void doSomething() {
　　System.out.println(&quot; PlantB do something ...&quot;);
　}
}
// 工厂方法接口
public interface IFactory {
　public IPlant createPlant();
}
//具体工厂方法
public class FactoryA implements IFactory {
　public IPlant createPlant() {
　　return new PlantA();
　}
}
public class FactoryB implements IFactory {
　public IPlant createPlant() {
　　return new PlantB();
　}
} 	

//客户端

IFactory plantFactory = new FactoryA();

IPlant planta = plantFactory.createPlant();

 planta.doSomething();

 

//若增加新产品PlantC时，只需要增加FactoryC工厂类和PlantC产品类即可。</pre>&nbsp;<p id="ff0a">此外，还有一个数字的加减乘除例子</p>
<p id="xne:"><br /><strong>五、工厂方法模式与简单工厂模式</strong><br /><br />　　工厂方法模式与简单工厂模式再结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类，而简单工厂模式把核心放在一个具体类上。 <br /><br />　　工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口，或者有共同的抽象父类。<br /><br />　　当系统扩展需要添加新的产品对象时，仅仅需要添加一个具体对象以及一个具体工厂对象，原有工厂对象不需要进行任何修改，也不需要修改客户端，很好的符合了&quot;开放－封闭&quot;原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法，扩展性不好。<br /><br />　　工厂方法模式退化后可以演变成简单工厂模式</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179616#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</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, 05 Apr 2008 10:33:01 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179616</link>
        <guid>http://luchar.javaeye.com/blog/179616</guid>
      </item>
      <item>
        <title>Java设计模式之简单工厂模式</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179614" style="color:red;">http://luchar.javaeye.com/blog/179614</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
                <span style="font-family: 宋体"><span style="font-weight: bold">一、概述 </span>&nbsp;  <br />
简单工厂模式</span><span style="font-family: 宋体">（Simple
Factory）</span><span style="font-family: 宋体">，又称静态工厂方法模式，是类的创建模式。</span>简单工厂模式专门定义一个类来负责创建其他类的实例，被创建的实例通常都具有共同的父类<br /><span style="font-family: 宋体">详细说明如下：<br />&nbsp;&nbsp;&nbsp; </span>一个具体工厂<span style="color: #ff0000">通过条件语句创建多个产品</span>，产品的创建逻辑集中与一个工厂类。<br />&nbsp;&nbsp;&nbsp;&nbsp;客户端通过<span style="color: #ff0000">传不同的参数给工厂</span>，实现创建不同产品的目的<br />&nbsp;&nbsp;&nbsp;&nbsp;增加新产品时，需要修改工厂类、增加产品类，不符合OCP原则<br />
<br />
<span style="font-weight: bold">二、具体代码</span><br /><pre name="code" class="java">//生产产品的工厂类
public class ProductFactory{
　　public static Product generateProduct(int which){ //这个方法是static的
　　if (which==1)
　　　　return new ProductA();
　　else if (which==2)
　　　　return new ProductB();
　　}
}

//抽象产品
public interface Product {
     .....
}

//具体产品A
public ProductA implement Product {
     ProductA () {}
}

//具体产品B
public ProductB implement Product {
     ProductB () {}
}

//调用工厂方法
public Client {
     public method1() {
         ProductFactory.generateProduct(1);
     }
}

</pre>&nbsp;<pre name="code" class="java">interface a{}

class b implements a{};

class c implements a{};

//工厂类
public class factory{
     public static a createa(string name){
         class cls=class.forname(name);
         object obj=cls.getinstance();
         return (a)obj;
     }
}
//创建实例时
a　b=factory.createa(&quot;b&quot;);
a  c=factory.createa(&quot;c&quot;); </pre>&nbsp;      
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179614#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/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Apr 2008 10:28:34 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179614</link>
        <guid>http://luchar.javaeye.com/blog/179614</guid>
      </item>
      <item>
        <title>设计模式中的一般原则</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179606" style="color:red;">http://luchar.javaeye.com/blog/179606</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h3 id="ky-u">如何学习设计模式？ </h3><p><span style="font-family: 宋体"><span style="color: #000000">1 先理解概念，再学习原则</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">先理解OO的基本概念，比如：封装、继承、多态、组合/聚合、依赖等，理解各概念的内涵，弄清楚这些概念的具体实现方式及各实现方式的优缺点。</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">2 先学习原则，再学习模式</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">设计原则是蕴含在设计模式后最根本的思想，掌握了基本的设计原则可以做到不拘泥于某个具体的设计模式，可以更容易的理解设计模式，知道在何种情况下应该采用某种模式，可以自己创造合理的设计模式。设计原则可以参考的2本书籍是《敏捷软件开发》与《UML与模式应用》。</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">3 从责任分配的角度学习设计模式</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">责任驱动的思想是学习设计模式的很好的思想，通过给各个类合理的分配实现某个需求的责任来理解设计模式。</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">4 类图与交互图并重</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">不要仅仅关注类图，类图仅仅是表达了类之间的静态关系，而交互图表达了对象之间的动态关系，可以看到对象与对象是如何写作完成一项事务。</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">5 从重构到模式</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">设计模式是一种固定的设计套路，是基于实践总结出来的可复用的解决方案，是一种经验的总结结果，如果仅仅看到最终的结果往往无法体会其用意，通过不断对某个需求的实现方案进行重构，得到最终的设计模式，可以对设计模式的背后的思想理解的更深刻。</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">6 记住典型案例</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">&nbsp; 通过类比，通过隐喻，通过记住某个典型案例，可以得到对设计模式的感性认识。</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体"><span style="color: #000000">7 从客户的角度考虑如何使用</span></span><span style="font-family: 宋体"><span style="color: #000000"><br /></span></span><span style="font-family: 宋体"><br /></span><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 在理解设计模式时，一定要从使用这些类的客户的角度来考虑是如何使用的？这样可以更容易理解该模式是如何对客户来封装的，实现了哪些封装，为了实现这些封装，采用了哪些手法？</span></p><p>&nbsp;</p><p><span style="color: #ff0000"><strong>在学习设计模式之前，最好先了解一下面向对象设计中的一些原则。</strong></span></p><p id="sz6q"><strong>一、 &quot;开放－封闭&quot;原则(OCP) </strong><br />&nbsp;&nbsp;&nbsp;&nbsp;
Open-Closed Principle原则讲的是：一个软件实体（类、模块、函数等等）应该可以扩展，但是不可修改。</p><p id="sz6q">&nbsp;&nbsp;&nbsp;
我们在做任何系统的时候，都不要指望系统一开始时需求确定，就再也不会变化，这是不现实也不科学的想法；儿既然需求是一定会变化的，那么如何在面对需求的
变化时，设计的软件可以相对容易修改，不至于说，新需求一来，就要把整个程序推到重来。怎样的设计才能面对需求的改变却可以保持相当稳定，从而使得系统可
以在第一个版本以后不断推出新的版本呢？这就要求我们遵循OCP原则，多扩展，少修改。面对新需求，对程序的改动是通过增加新代码进行的，而不是更改现有
的代码。通过扩展已有软件系统，可以提供新的行为。而对已有软件模块，特别是最重要的抽象层模块不能再修改，这使变化中的软件系统有一定的稳定性和延续
性。 </p><p id="sz6q">&nbsp;&nbsp;&nbsp;
开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处，也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅
对程序中呈现出频繁变化的那些部分做出抽象，然而，对于应用程序中的每个部分都刻意地进行抽象同样不是一个好注意。拒绝不成熟的抽象和抽象本身一样重要。</p>
举例：一国两制 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
为实现祖国统一，邓小平提出&ldquo;一国两制&rdquo;的构想，这是一个很好的&ldquo;开闭原则&rdquo;。&ldquo;一国&rdquo;是封闭，即坚持一个中国的前提，这一点不能变，用中央的话来说就是
&ldquo;在一个中国的前提下什么都可以谈&rdquo;。而&ldquo;两制&rdquo;就是开放，你走你的资本主义道路，我走我的社会主义道路。 &ldquo;一国两制&rdquo;不允许更改现有一个中国的秩序，将资本主义制度纳入现有的政治制度中，从而扩展了这一秩序。用面向对象的语言来讲，不允许更改的是系统的抽象层，而允许更改的是系统的实现层。 <p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179606#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><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Apr 2008 09:05:30 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179606</link>
        <guid>http://luchar.javaeye.com/blog/179606</guid>
      </item>
      <item>
        <title>Java设计模式之综述篇</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/179605" style="color:red;">http://luchar.javaeye.com/blog/179605</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span class="main">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自从<a href="http://www.csai.cn/incsearch/search.asp?key=J2EE" id="r4b9" target="_blank">J2EE</a>出现以来，就大大简化了在<a href="http://www.csai.cn/incsearch/search.asp?key=Java" id="il4z" target="_blank">Java</a>下的企业级开发。但是随着J2EE越来越普遍地被应用到各个领域中，开发者们渐渐意识到需要一种方法来<a href="http://www.csai.cn/incsearch/search.asp?key=%B1%EA%D7%BC" id="i0jg" target="_blank">标准</a>化应用程序的开发过程，他们采用的方法是标准化应用程序的结构层。在结构层通常封装了一些独立于业务逻辑的复杂技术，以便在业务逻辑和底层的架构之间建立起弱连接。在个<a href="http://www.csai.cn/incsearch/search.asp?key=%D7%A8%CC%E2" id="jdpp" target="_blank">专题</a>中将会介绍一些<u>设计</u>模式，通过利用这些设计模式，开发人员可以达到标准化和简化应用<a href="http://www.csai.cn/incsearch/search.asp?key=%B3%CC%D0%F2%BF%AA%B7%A2" id="ehvy" target="_blank">程序开发</a>过程的目的。 </span>
<p class="main" id="vuc5"><span style="color: #ff0000">　　</span><strong>应用程序结构和J2EE</strong></p>
<p class="main" id="wfrs">　　J2EE是一个很成功的技术，它为一些基本的任务提供了一致的标准，例如数据库连接、<a href="http://www.csai.cn/incsearch/search.asp?key=%B7%D6%B2%BC%CA%BD" id="r_is" target="_blank">分布式</a>应用程序等。但是使用J2EE并不能保证开发人员开发出成功的应用程序。有些人认为J2EE本身就是一种框架技术，但是这种认识是不正确的，我们应该意识到J2EE并没有提供一个能够帮助开发人员开发出高<u>质量</u>应用程序的框架，因此很多有经验的开发人员通过利用设计模式来弥补这一缺项。 </p>
<p class="main" id="rf_2"><span style="color: #ff0000">　　</span><strong>设计模式</strong></p>
<p class="main" id="s39j">　　在开发人员的圈子中，大家通过相互交流在开发过程中所遇到的问题以及解决方法来丰富整个圈子的
经验。而设计模式就是在这样的情况下产生的。一个设计模式必然是针对某个特定的问题的，这个问题的解决方案以及这样解决问题产生的后果。在解决利用
J2EE进行程序开发中出现的问题的过程中，人们把设计模式分为两类，一种是通用开发模式，一种是为了解决特定的J2EE问题的模式。下面让我们来看一看
每一种类型的开发模式都包含了哪些内容。 </p>
<p class="main" id="p65z"><span style="color: #0000ff">　　<strong>J2EE设计模式</strong></span> </p>
<p class="main" id="lhq2">　　J2EE设计模式在过去几年中随着Java开发人员经验的不断成长而发展。这些设计模式是针对
使用各种J2EE技术时可能出现的问题提出的，它们能够帮助开发人员构造出应用程序框架的要求。例如，Front
Controller（前端控件）模式将servlet代码的开发转化为在图形用户界面下的开发。但是需要记住J2EE设计模型解决了那些在J2EE项目
中最可能出现的问题。如果你在J2EE遇到的问题很特殊，很有可能没有相应的设计模型来解决它。 </p>
<p class="main" id="eq0r"><span style="color: #0000ff">　　<strong>软件开发设计模式 </strong></span></p>
<p class="main" id="qmih">　　软件开发设计模式又被分为两种，一种是通用的面向对象设计模式。例如工厂（Factory）模式是一种面向对象的设计模式，它将对象的创建封装起来，使对象能够重用，这样就可以减少程序占用的系统<a href="http://www.csai.cn/incsearch/search.asp?key=%D7%CA%D4%B4" id="nhe0" target="_blank">资源</a>。而另一种是基于Java的设计模式，这些设计模式要么是和Java的语言特性结合得很紧，要么是<a href="http://www.csai.cn/incsearch/search.asp?key=%C3%E6%CF%F2%B6%D4%CF%F3%BC%BC%CA%F5" id="fp6g" target="_blank">面向对象技术</a>在Java中的深化。不要以为软件设计模式相对独立于J2EE就认为它们不重要，通常它们比J2EE设计模式更重要。这是因为： </p>
<p class="main" id="r4m3">　　1）J2EE设计模式是近几年才出现的，并且在不断变化，而软件开发设计模式经过了长时间的考验，比前者更加成熟和完善； </p>
<p class="main" id="t7tg">　　2）有些J2EE设计模式是建立在某些软件开发设计模式之上的； </p>
<p class="main" id="r350">　　3）软件开发模式为J2EE设计模式提供了坚实的基础。它的应用将影响到整个结构的稳定性和可扩充性。 </p>
<p class="main" id="girb">　　在实际应用中，设计模式并不是一段具体的代码。设计模式通常是在设计说明书中描述。将设计模式应用到系统中的真正挑战在于如何在系统中应用模式中的思想。这些思想必须被应用到恰当的环境中。 </p>
<p class="main" id="oc9f">　　根据设计模式的所解决的问题，又可以分为以下几个类型： </p>
<p class="main" id="xl:d">　　&middot; 创建类型：创建类型的模式都是用于创建类的实例。但是和通过new来创建实例不同，这些模式提供了更加灵活的方式，是程序能够根据特定的情况创建特定的类。 </p>
<p class="main" id="uhsf">　　&middot; 结构类型：结构类型的模式帮助开发人员将简单对象组合在一起以后的更加复杂的结构。 </p>
<p class="main" id="z8sm">　　&middot; 行为类型：行为类型的模式帮助开发人员控制类之间的通讯。 </p>
<p class="main" id="hp.7"><span style="color: #0000ff">　　<strong>创建类型的模式</strong> </span></p>
<p class="main" id="n-ql">　　所有创建类型的模式都和如何有效地创建类的实例相关。在Java中，如果开发人员要生成一个类的实例，最简单的方法是使用new关键字： </p>
<p class="main" id="hc8e">　　MyFoo = new Foo(); // 生成一个Foo的实例 </p>
<p class="main" id="ya-h">　　这种方法只能够在程序中生成固定的类。但是在很多情况下，程序需要根据不同的情况生成不同的类的实例，这就需要将实例的生成过程抽象到一个特殊的创建类中，由该类在运行时决定生成哪种类的实例。这样使得程序有更好的灵活性和通用性。 </p>
<p class="main" id="qxme">　　创建类型的模式包括： </p>
<p class="main" id="g5b5">　　&middot; 简单工厂模式（Factory Pattern）：根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例，而这一组类有一个公共的抽象父类。</p>
<p class="main" id="g5b5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 工厂方法模式</p>
<p class="main" id="c6j-">　　&middot; 抽象工厂模式（Abstract Factory Pattern）：抽象工厂模式也可以根据提供的数据生成一组类中某一个类的实例，而这一组类有一个公共的抽象父类。只不过它定义的是一个接口。 例如：多数据库，多个表的访问</p>
<p class="main" id="x7md">　　&middot; 构造者模式（Builder Pattern）：构造者模式将一个复杂对象的构造过程和它的表现层分离开来，这样类就可以根据不同情况展现出不同的表现方式。 </p>
<p class="main" id="mdse">　　&middot; 原型模式（Prototype Pattern）：原型模式通过对类的实例进行拷贝来创建新的实例。 </p>
<p class="main" id="ne-8">　　&middot; 单一模式（Singleton Pattern）：根据单一模式实现的类只允许有一个是类，并且提供了一个全局指针来引用该实例。 </p>
<p class="main" id="k:i."><span style="color: #0000ff">　　<strong>结构类型的模式 </strong></span></p>
<p class="main" id="pdnh">　　结构类型的模式将类和对象组合起来，以构成更加复杂的结构。它又被划分为类模式和对象模式。类模式和对象模式之间的区别在于类模式通过继承关系来提供有效的接口；而类模式通过对象合成或将对象包含在其它对象中的方式构成更加复杂的结构。 </p>
<p class="main" id="la2o">　　结构类型的模式包括了以下模式： </p>
<p class="main" id="pu80">　　&middot; 适配器模式（Adapter Pattern）：适配器模式可以将一个类的接口和另一个类的接口匹配起来。 </p>
<p class="main" id="jrry">　　&middot; 桥梁模式（Bridge Pattern）：桥梁模式对客户端程序提供一个固定的接口，但是允许开发人员变化实际的实现类。这样开发人员就可以将接口是具体的实现类分离开来。 </p>
<p class="main" id="szbg">　　&middot; 复合模式（Composite Pattern）：复合模式可以将多个对象进行复合，其中的每个对象可以是简单对象，也可以是复合对象。 </p>
<p class="main" id="f4wk">　　&middot; 代理模式（Proxy Pattern）：代理模式利用一个简单的对象替代一个复杂的对象，当复杂对象在需要的时候才会被加载到系统中，这样可以节约系统资源，提高系统的响应速度。在网络环境中这种模式很有用处。 </p>
<p class="main" id="alr4">　　&middot; 修饰模式（Decorator Pattern）：通过修饰模式，开发人员可以在运行时将特定的功能绑定在对象上。 </p>
<p class="main" id="ilcn">　　&middot; 轻量模式（Flyweight Pattern）：轻量模式通过将对象中的一部分数据保存在对象外，在调用对象中的方法时再将这些数据传回对象。这样做可以减少大量比较简单的对象占用的空间。 </p>
<p class="main" id="i35u">　　&middot; 正面模式（Fa?ade Pattern）：正面模式将复杂的类层次结构组织起来，通过一个简单的接口来获得层次结构中的数据。 </p>
<p class="main" id="upt2"><span style="color: #0000ff">　　<strong>行为类型的模式</strong> </span></p>
<p class="main" id="mx_l">　　行为类型的模式主要是那些处理对象之间通讯的模式，该类型的包括以下模式： </p>
<p class="main" id="zehg">　　&middot; 观测者模式（Observer Pattern）：观测者模式可以在发生变化时将变化通知多个类。 </p>
<p class="main" id="vzdd">　　&middot; 中介模式（Mediator Pattern）：中介模式可以通过一个中间类来控制若干个类之间的通讯，并且这些类相互之间不需要了解对方的信息。 </p>
<p class="main" id="lfic">　　&middot; 回忆模式（Memento Pattern）：回忆模式可以在不破坏对象封装性的前提下保存和恢复对象的内部状态。 </p>
<p class="main" id="lvve">　　&middot; 职责链模式（Chain of Responsibility）：职责链模式将请求传递给一组对象，只有特定的对象才会处理该请求。这样就进一步削弱类之间的联系。 </p>
<p class="main" id="z70i">　　&middot; 命令模式（Command Pattern）：命令模式将请求传递给特定的对象，这样客户端即使在不知道<a href="http://www.csai.cn/incsearch/search.asp?key=%B7%FE%CE%F1%C6%F7" id="u.4." target="_blank">服务器</a>端如何处理请求的情况下也可以发送请求。 </p>
<p class="main" id="r4d-">　　&middot; 模板模式（Template Pattern）：模板模式提供了对算法的抽象定义。 </p>
<p class="main" id="l40b">　　&middot; 策略模式（Strategy Pattern）: 策略模式定义了一组算法，将每个算法都封装起来，并且使它们之间可以互换。策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。 </p>
<p class="main" id="q:j2">　　&middot; 访问者模式（Visitor Pattern）：访问者模式通过一个访问类来访问其他类中的数据。 </p>
<p class="main" id="q5g0">　　&middot; 状态模式（State Pattern）：状态模式将一个类实例的变量保存在独立的内存空间中。 </p>
<p class="main" id="r6nu">　　&middot; 迭代模式（Iterator Pattern）：迭代模式在不知道数据的内部表现形式的前提下，通过标准的接口来遍历数据集合中的数据。</p>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/179605#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><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><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Apr 2008 09:02:03 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/179605</link>
        <guid>http://luchar.javaeye.com/blog/179605</guid>
      </item>
      <item>
        <title>windows下Apache+SVN+Trac安装及配置（二）</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/151051" style="color:red;">http://luchar.javaeye.com/blog/151051</a>&nbsp;
          发表时间: 2007年12月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在Trac的官网上有有一篇安装指南，针对Trac0.11版本的。上面可以看到这时0.11的正式版还没有发布，我安装的是0.11b1版的。<a href="http://trac.edgewall.org/wiki/TracInstall#TracInstallationGuidefor0.11" title="http://trac.edgewall.org/wiki/TracInstall#TracInstallationGuidefor0.11" id="zgqj">http://trac.edgewall.org/wiki/TracInstall#TracInstallationGuidefor0.11</a> 一、Trac简介<br />
Trac是一个轻量级的项目管理工具，是一个基于web的应用程序。Trac是用Python语言开发的，需要数据库( <a href="http://sqlite.org/" class="ext-link">SQLite</a>, <a href="http://www.postgresql.org/" class="ext-link">PostgreSQL</a>, <a href="http://mysql.com/" class="ext-link">MySQL</a> 等).的支持才能运行。对于HTML渲染，在Trac 0.11版本之前用的是<a href="http://docs.google.com/wiki/ClearSilver" class="wiki">ClearSilver</a>，以后推荐用的是<a href="http://genshi.edgewall.org/" class="ext-link">Genshi</a><br />
<br />
二、安装必备的软件<br />
注意软件的版本及安装的顺序<br />
1.安装<a href="http://www.python.org/" class="ext-link">Python</a>,下载：python-2.5msi，默认安装   <br />
2.安装<a href="http://genshi.edgewall.org/wiki/Download" class="ext-link">Genshi</a>模板系统，属于页面表示层，下载Genshi-0.4.4.win32.exe，安装时会识别Python安装目录。<br />
3.安装Subversion Python Bindings ：svn-python-1.4.6.win32-py2.5.exe，安装时会识别Python安装目录。<br />
4.安装<a href="http://pysqlite.org/" class="ext-link">PySQLite</a>, 下载pysqlite-2.4.0.win32-py2.5.exe， 安装时会识别Python安装目录。PySQLite是SQLite和Python 绑定的轻量级数据库引擎，它是Trac默认的数据库。<br />
<br />
三、安装Trac(0.11dev) <br />
由于我用的都是最新版本的软件，安装Trac时浪费了很多时间，后来还是看官网上的文章才搞定。<br />
1.最好添加python的环境变量（C:\Python25）到path中<br />
2.确保先安装<a href="http://peak.telecommunity.com/DevCenter/EasyInstall#installation-instructions" class="ext-link">setuptools</a> ，安装步骤如下：在主页中将<a href="http://peak.telecommunity.com/dist/ez_setup.py" class="reference">ez_setup.py</a>文件下载保存下来（如放在c:\src下面），命令行进入该目录执行python ez_setup.py即可安装和python版本对应的setuptools。<br />
3.check出Trac版本库，再安装，完整的执行语句如下：       <br />
<pre class="wiki" style="background-color: rgb(255, 255, 255);"><div><table cellspacing="0" id="ud44" border="0" height="88" cellpadding="3" width="547"><tbody><tr><td width="100%"><pre class="wiki">&gt; cd C:\src<br />&gt; python ez_setup.py<br />&gt; svn checkout http://svn.edgewall.org/repos/trac/trunk<br />&gt; cd trunk<br />&gt; python setup.py ins</pre>
</td>
</tr>
</tbody>
</table>
</div>
</pre>
四、配置Trac环境<br />
完成上述的安装后，就可以创建一个<font color="#3366ff"><a href="http://trac.edgewall.org/wiki/TracEnvironment" class="wiki">TracEnvironment，</a></font>它是Trac存储信息的地方，如 wiki pages, tickets, reports, settings, 等。<br />
1. 通过<a href="http://docs.google.com/wiki/TracAdmin" class="wiki">trac-admin</a>创建一个Trac Environment<br />
<pre class="wiki">            我的做法是先在d盘新建一个trac目录，然后执行：<span style="background-color: rgb(192, 192, 192);">&gt; trac-admin d:/trac/mytest initenv</span><br />     然后根据提示输入项目的名字(myproject)，数据库连接字符串（默认），你的源代码资源库路径。<br />  2.在8080端口上单项目运行<br />    <div><table cellspacing="0" id="itg_" border="0" height="26" cellpadding="3" width="553"><tbody><tr><td width="100%">&gt; cd C:\Python25\Scripts<br />&gt; tracd -p 8080 d:/trac/mytest</td></tr></tbody></table></div>    当看到 <span style="background-color: rgb(192, 192, 192);">Serving on 0.0.0.0:8080 view at http://127.0.0.1:8080/ <span style="background-color: rgb(255, 255, 255);">时，就表示服务器启动成功了，可以打开浏览器，<br />看到如下效果图：<br /><div id="moeh" style="padding: 1em 0pt; text-align: left;"><img src="http://docs.google.com/File?id=df2ff8cn_214dg9z72fx" height="306" alt="" width="673" /></div>五、Apache+SVN与Trac集成<br />    上面的配置是运行在一个独立的服务器上，只能运行一个项目，一般只用于自己单机访问。考虑到我们前面安装的SVN是运<br />行在Apache服务器上，我们最好也让Trac运行在Apache服务器上，便于网上共享；而且和Apache集成有很多优点，</span></span>比如充分利用<br />apache的强大功能以及ModPython的高效率，便于管理与控制，很方便支持ssl等等。<span style="background-color: rgb(192, 192, 192);"><span style="background-color: rgb(255, 255, 255);">在官方网站上提供的安装指南上面提供了三<br />种方法</span></span><a href="http://trac.edgewall.org/wiki/TracCgi" class="wiki">CGI</a>, <a href="http://trac.edgewall.org/wiki/TracFastCgi" class="wiki">FastCGI</a> and <font color="#3366ff"><a href="http://trac.edgewall.org/wiki/TracModPython" class="wiki">mod_python</a></font>.为了提高性能，推荐使用后面两种，我安装时采用第三种。<br /><span style="background-color: rgb(192, 192, 192);"><span style="background-color: rgb(255, 255, 255);"><br />1、在<a href="http://www.modpython.org/" title="http://www.modpython.org/" id="bv2:">http://www.modpython.org/</a> 页面下载相应的安装程序，注意版本对应。我下载的是<br />mod_python-3.3.1.win32-py2.5-Apache2.2.exe，然后安装，</span></span>安装过程中会要求选择apache的安装目录，并且自动把<br />mod_python.so复制到modules目录 <span style="background-color: rgb(192, 192, 192);"><span style="background-color: rgb(255, 255, 255);">。完成后还要进行配置，类似于SVN和apache的集成，我主要参考的是官方文档。</span></span><span style="background-color: rgb(192, 192, 192);"><span style="background-color: rgb(255, 255, 255);"><br /></span></span></pre>
<p>2、配置</p>
<ul>
    <li>配置ModPython<br />
    在apache的httpd.conf中加入下面一行：<br />
    <font color="#ff6666">LoadModule python_module  modules/mod_python.so</font>  </li>
    <li>配置trac<br />
    在apache的httpd.conf中加入下面内容：<br />
    #setup trac on mod_python<br />
    <location><span style="background-color: rgb(192, 192, 192);">/trac/mytest</span>&gt;<br />
    SetHandler mod_python<br />
    PythonInterpreter main_interpreter<br />
    PythonHandler trac.web.modpython_frontend <br />
    PythonOption TracEnv <span style="background-color: rgb(192, 192, 192);">d:/trac/mytest   <font color="#ff0000">#根据个人安装情况修改</font></span><br />
    PythonOption TracUriRoot /trac/mytest<br />
    </location>  </li>
    <li>然后就通过<a href="http://localhost/trac">http://localhost/trac/myjava</a>来访问，点击&ldquo;浏览源代码&rdquo;就可以看到svn库中项目资源。</li>
</ul>
<pre class="wiki"><span style="background-color: rgb(192, 192, 192);"><span style="background-color: rgb(255, 255, 255);">3、</span></span>配置用户身份的验证<br /></pre>
<p>      Trac可以使用Apache的身份验证。</p>
<ul>
    <li>创建密码文件,如为myjava创建密码文件，javatrac为用户名：<br />
    转到%Apache%\bin&gt;<font color="#000000" style="background-color: rgb(192, 192, 192);">htpasswd -c </font><span style="background-color: rgb(192, 192, 192);">d:/trac/mytest/</span><font color="#000000" style="background-color: rgb(192, 192, 192);">conf/trac.passwd javatrac</font><br />
    New password: ****<br />
    Re-type new password: ****<br />
    Adding password for  user zhengjian<strong><br />
    若对密码不想加密可使用-cp参数，win平台下默认是MD5加密。</strong>   </li>
    <li><br />
    </li>
    <li>配置身份验证                                                                                                                                                                                                                               #设置myjava的Trac用户验证<br />
    <location><span style="background-color: rgb(192, 192, 192);">/trac/mytest/login</span>&gt;<br />
    AuthType Basic<br />
    AuthName myjavatrac<br />
    AuthUserFile <span style="background-color: rgb(192, 192, 192);">d:/trac/mytest/conf/trac.passwd</span><br />
    Require valid-user<br />
    </location>                                                                                                                                                                                                                                   <br />
    </li>
</ul>
完成后重启Apache服务器，然后浏览<a href="http://localhost:8080/trac/mytest" title="http://localhost:8080/trac/mytest" id="rmmn">http://localhost:8080/trac/mytest</a> ,点击Login，将看到如下效果图： <br />
<div id="qebr" align="left" style="padding: 1em 0pt; text-align: left;"><img src="http://docs.google.com/File?id=df2ff8cn_215g9cqgzg7" alt="" style="width: 328px; height: 290px;" /></div>
4、Trac的授权设置<br />
在Trac 0.11以前的版本需要安装WebAdmin插件才能以web的方式管理用户及授权，以后的版本就不在需要了，已经集成了。前面创建的Apache的身份验证，都不具有TRAC_ADMIN权限，下面我们<br />
新创建一个admin用户，然后授予TRAC_ADMIN权限：<br />
<div>
<table cellspacing="0" id="lj8k" border="0" height="180" cellpadding="3" width="637">
    <tbody>
        <tr>
            <td width="100%">#创建一个admin用户<br />
            命令行转到%Apache%\bin&gt;<font color="#000000" style="background-color: rgb(192, 192, 192);">htpasswd -c </font><span style="background-color: rgb(192, 192, 192);">d:/trac/mytest/</span><font color="#000000" style="background-color: rgb(192, 192, 192);">conf/trac.passwd admin</font><br />
            New password: *****<br />
            Re-type new password: *****<br />
            Adding password for  user admin<br />
            <br />
            #为admin用户授权TRAC_ADMIN<br />
            &gt;<span style="background-color: rgb(192, 192, 192);">cd c:/python25/Scripts</span><br />
            &gt;<span style="background-color: rgb(192, 192, 192);">trac-admin d:/trac/mytest permission         add admin TRAC_ADMIN  <span style="background-color: rgb(255, 204, 204);">#该命令执行时有异常，但不影响授权，我也不知道是哪里的问题</span></span> </td>
        </tr>
    </tbody>
</table>
</div>
完成后再以admin帐号Login，在search的后面就会看到Admin，点击进入可以看到如下效果图：<br />
<div id="vd69" style="padding: 1em 0pt; text-align: left;"><img src="http://docs.google.com/File?id=df2ff8cn_217dbfbmbf5" height="508" alt="" width="674" /></div>
至此，Apache+SVN+Trac的集成到此完毕了，由于我用都是目前最近的版本，花费了我将近3天的时间，虽然界面都还是英文的，不过总算运行起来了，下面要做的就是仔细看看如何更好的利用了。我是第<br />
一次用这个管理跟踪项目，欢迎大家相互探讨。<br />
<br />
参考：<br />
<a href="http://trac.edgewall.org/wiki/TracInstall#Short-Installareleasedversion" target="_blank">http://trac.edgewall.org/wiki/TracInstall#Short-Installareleasedversion</a><br />
<a href="http://blog.chinaunix.net/u/30647/showart_240570.html" target="_blank">http://blog.chinaunix.net/u/30647/showart_240570.html</a><br />
<a href="http://www.hamo.cn/archives/397.html" target="_blank">http://www.hamo.cn/archives/397.html</a><span style="background-color: rgb(192, 192, 192);"><span style="background-color: rgb(255, 255, 255);"><br />
<a href="http://www.yi-dao.com/wiki/ow.asp?Trac" target="_blank">http://www.yi-dao.com/wiki/ow.asp?Trac</a><br />
</span></span>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/151051#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/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 26 Dec 2007 21:04:01 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/151051</link>
        <guid>http://luchar.javaeye.com/blog/151051</guid>
      </item>
      <item>
        <title>windows下Apache+SVN+Trac安装及配置（一）</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/151049" style="color:red;">http://luchar.javaeye.com/blog/151049</a>&nbsp;
          发表时间: 2007年12月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然原来也在使用Subversion，但使用的不是http服务器，用的是把svnservice.exe安装成window服务的方式。原来的开发环 境配置一直不统一，这次花的功夫好好弄一下，想搭建一个全部基于开源的Apache+SVN+Trac的配置，希望能给自己不一样的感觉。本文先说 Apache和SVN的集成,下一篇再集成Trac。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 安装过程还是有点复杂的，可能是我用的都是最新版本的缘故，网上的好多文章目前没有针对最新版本的，好在大致相当，问题不大。<br />
一.准备安装软件
<ul>
    <li>先下载Http服务器，官方网站为<a href="http://httpd.apache.org/" title="http://httpd.apache.org/" id="la84">http://httpd.apache.org/</a> ，目前最新版本为<font color="#ffffff" face="arial,helvetica,sanserif"><a name="2.2.6"><strong><font color="#000000">Apache  2.2.6，我下载的是apache_2.2.6-win32-x86-no_ssl.msi</font></strong></a></font></li>
</ul>
<ul>
    <li>再下载SVN服务器，官方网站为<a href="http://subversion.tigris.org/" title="http://subversion.tigris.org/" id="wd5e">http://subversion.tigris.org/</a> ，最新版本为Subversion 1.4.6，可能是才发布，还没有安装程序，只有二进制解压版的，下载时要注意下载和Apache2.2.x版本对应的，我下载的是svn-win32- 1.4.6.zip；同时下载svn-python-1.4.6.win32-py2.5.exe</li>
    <li><strong>TortoiseSVN</strong>，客户端程序。TortoiseSVN是扩展Windows  Shell的一套工具，可以看作Windows资源管理器的插件，安装之后Windows就可以识别Subversion的工作目录，点鼠标右键即可看到。网址为<a href="http://tortoisesvn.tigris.org/" title="http://tortoisesvn.tigris.org/" id="bn84">http://tortoisesvn.tigris.org/</a> ，我下载的是TortoiseSVN-1.4.6.11647-win32-svn-1.4.6.msi</li>
    <li><strong>TortoiseSVN的中文语言包</strong>，注意这个需要下和客户端程序版本相同的。这个可以在language packs下面下载。<br />
    <font color="#ffffff" face="arial,helvetica,sanserif"><a name="2.2.6"></a></font></li>
</ul>
<font color="#ffffff" face="arial,helvetica,sanserif"><a name="2.2.6"> </a></font>&nbsp;&nbsp;&nbsp;  <br />
二. 安装<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.先安装Apache服务器。自己手动填写ServerInfo。安装完成之后到安装目录下找到conf目录下的httpd.config文件，搜索 Listen，并将Listen后面的80改为8080（或者你希望的端口），然后重新启动Apache服务器，这时可以用<a href="http://localhost:8080/">http://localhost:8080</a> 来测试是否安装正确。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.再安装SVN服务器，直接解压即可。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.安装TortoiseSVN，很简单，一路安装下去。<br />
<br />
三. 集成Apache和SVN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<ol>
    <li>首先将<font face="Times New Roman, serif">Subversion</font>安装目录<font face="Times New Roman, serif">bin\</font>下面的两个文件：<font face="Times New Roman, serif"><strong>mod_authz_svn.so</strong></font>和<font face="Times New Roman, serif"><strong>mod_dav_svn.so</strong></font>复制到<font face="Times New Roman, serif">Apache</font>安装目录<font face="Times New Roman, serif">modules\</font>目录下； 再将<font face="Times New Roman, serif">Subversion</font>安装目录<font face="Times New Roman, serif">bin\</font>下面的<font color="#cc0000">所有.dll文件</font>复制到<font face="Times New Roman, serif">Apache</font>安装目录<font face="Times New Roman, serif">bin\</font>目录下 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </li>
    <li>需要再修改httpd.conf，并做如下修改：<br />
    找到Apache安装目录下的conf目录，用文本编辑器打开httpd.conf，找到一下两行：<br />
    <br />
    <font style="background-color: rgb(169, 169, 169);">#LoadModule dav_module  modules/mod_dav.so<br />
    #LoadModule dav_fs_module  modules/mod_dav_fs.so<br />
    </font><br />
    将每行前面的注释符&ldquo;#&rdquo;去掉。再在所有LoadModule语句的最后添加一下几行：<br />
    <br />
    <font style="background-color: rgb(169, 169, 169);">#SVN<br />
    LoadModule dav_svn_module  modules/mod_dav_svn.so<br />
    LoadModule authz_svn_module  modules/mod_authz_svn.so<br />
    </font><br />
    如图：<br />
    <div id="q:ki" style="padding: 1em 0pt; text-align: left;"><img src="http://docs.google.com/File?id=df2ff8cn_2184pc25mfx" alt="" style="width: 531px; height: 339px;" /></div>
    <br />
    注意下面的状态栏已经是Apache/2.2.6 SVN1.4.6 DAV/2<br />
    <br />
    </li>
    <li>建立一个SVN存放文件的目录，我在D盘下创建一个文件夹：D:/svn</li>
    <li>接下来我们必须告诉Apache我们的资源 库所在的路径，可以通过Location指令来完成这个设置。因为不希望为每个单独的项目都进行单独的设置，所以我们把所有项目都存放在统一的资源库目 录，那么可以使用SVNParentPath指令来指定存放所有项目的路径。在httpd.conf文件最后添加下面配置：&nbsp; <br />
    #SVN<br />
    &lt;Location /svn&gt;<br />
    &nbsp;&nbsp;&nbsp; DAV svn<br />
    &nbsp;&nbsp;&nbsp; SVNListParentPath on<br />
    &nbsp;&nbsp;&nbsp; SVNParentPath &quot;D:/svn&quot;<br />
    &nbsp;&nbsp;&nbsp; #SVNPath &quot;D:/svn/test&quot;<br />
    &nbsp; <br />
    &nbsp;&nbsp;&nbsp; ####################认证的类型<br />
    &nbsp;&nbsp;&nbsp; AuthType Basic<br />
    &nbsp;&nbsp;&nbsp; ####################认证的名称,显示于登录提示框<br />
    &nbsp;&nbsp;&nbsp; AuthName &quot;Subversion 资源库，请登录!&quot; <br />
    &nbsp;&nbsp;&nbsp; ####################Which password file to use for authentication 存储用户登录信息的文件<br />
    &nbsp;&nbsp;&nbsp; AuthUserFile D:\svn\passwd <br />
    &nbsp;&nbsp;&nbsp; ####################限定各个用户或组在版本库中目录的访问权限<br />
    &nbsp;&nbsp;&nbsp; AuthzSVNAccessFile D:\svn\svnaccessfile<br />
    &nbsp;&nbsp;&nbsp; ####################让所有用户对版本库都有读的权限而只有特定的用户才有写的权限<br />
    &nbsp;&nbsp;&nbsp; Require valid-user<br />
    &lt;/Location&gt;</li>
    <li>在命令行窗口中<strong>转到Apache所在的目录</strong>，执行下列命令,创建用户及密码<br />
    <font style="background-color: rgb(192, 192, 192);">说明：创建用户zj<br />
    输入：</font><span style="background-color: rgb(192, 192, 192);">htpasswd &ndash;c D:\svn\passwd zj</span><br style="background-color: rgb(192, 192, 192);" />
    <font style="background-color: rgb(192, 192, 192);">说明：使用-c参数来创建一个passwd文件<br />
    输出：<br />
    New password: *****<br />
    Re-type new  password: *****<br />
    Adding password for user zj</font><br />
    <p><font style="background-color: rgb(255, 255, 255);">再创建用户的时候就不用-c参数，而是用-m参数，因为文件</font><font style="background-color: rgb(255, 255, 255);"><strong>passwd</strong> 已</font><font style="background-color: rgb(255, 255, 255);">经创建。<br />
    </font></p>
    <p><font style="background-color: rgb(255, 255, 255);">打开passwd文件，密码使用MD5加密过了，而且同样的密码加密出来的内容却不相同。用</font>TortoiseSVN在D:/svn下创建test和java资源库.（很简单，不多说）</p>
    </li>
    <li>
    <p>然后用文本编辑器创建一个Subversion授权文件，文件名为svnaccessfile，内容如下：</p>
    [groups]<br />
    admin = john, kate<br />
    devteam1 = john, rachel, sally<br />
    devteam2 = kate, peter, mark<br />
    <br />
    # 为所有库指定默认访问规则<br />
    # 所有人可以读，管理员可以写，危险分子没有任何权限，[/]代表根目录<br />
    [/]<br />
    * = r<br />
    @admin = rw<br />
    dangerman =<br />
    <br />
    # 允许开发人员可以完全访问他们的项目版本库<br />
    [test:/]<br />
    @devteam1 = rw<br />
    [java:/]<br />
    @devteam2 = rw<br />
    </li>
    <li><font style="background-color: rgb(255, 255, 255);">保存好上面的所有配置文件之后，重新启动Apache服务器。此时我们就可以在IE里面通过</font><a href="http://localhost:8080/Test1"><font style="background-color: rgb(255, 255, 255);">http://localhost:8080/test</font></a><font style="background-color: rgb(255, 255, 255);"> 和</font><a href="http://localhost:8080/Test2"><font style="background-color: rgb(255, 255, 255);">http://localhost:8080/java</font></a><font style="background-color: rgb(255, 255, 255);"> 来测试用户登录，以及不同用户组权限。 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
    </font></li>
</ol>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/151049#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</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, 26 Dec 2007 20:59:55 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/151049</link>
        <guid>http://luchar.javaeye.com/blog/151049</guid>
      </item>
      <item>
        <title>简单RCP框架源码分析</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/145650" style="color:red;">http://luchar.javaeye.com/blog/145650</a>&nbsp;
          发表时间: 2007年12月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在我们新建一个RCP应用程序框架时，eclipse会为我们自动生成若干个类：<br />
<div id="zh:u" style="padding: 1em 0pt; text-align: left;"><img src="http://docs.google.com/File?id=df2ff8cn_129tbzk4xdv" alt="" style="width: 285px; height: 105px;" /></div>
网上也有很多关于&ldquo;Hello RCP&rdquo;的分析说明，但都聚集在类功能分析，没有源代码的分析。下面着重分析一下其中的某些不易理解的类以及其中涉及到的其它类的源代码。<br />
<ol>
    <li><font color="#ff0000">Application</font>类： 是RCP应用程序的入口点，你可以把它想象成程序的控制器，类似于Model2架构中的控制器。它很简短，而且在不同的项目中变化不大；它所做的就是创建 一个工作台Workbench，同时将其于一个WorkbenchAdvisor联系起来。Workbench是RCP框架的一部分，一个RCP应用对应 一个Workbench，但一个&nbsp;&nbsp;&nbsp;&nbsp; Workbench可以有多个Workbench窗口。</li>
    <li><font color="#ff0000">ApplicationWorkbenchAdvisor</font>类：继承了WorkbenchAdvisor类，提供了两个方法，其中createWorkbenchWindowAdvisor方法将创建窗口的工作交给了ApplicationWorkbenchWindowAdvisor类。</li>
    <li><font color="#ff0000">WorkbenchAdvisor</font>类： 该类不是一个接口，而是一个抽象类，它不包含任何的功能实现，因为将来很有可能在其中添加其它方法。Eclipse的设计者们希望每个RCP应用都实现 它，由平台来调用。Workbench和Workbench&nbsp;Window生命周期中的有一些重要事件，这些事件在WorkbenchAdvisor中都 有相应的方法，Platform调用这些方法从而执行你的定制代码。<br />
    <p>表1. WorkbenchAdvisor提供的事件处理方法</p>
    <table border="1">
        <tbody>
            <tr>
                <th>方法</th>
                <th>描述</th>
                <th>参数</th>
            </tr>
            <tr>
                <td>initialize</td>
                <td>第一个被调用，用来初始化，比如解析命令行，注册适配器，声明图像等。</td>
                <td><code>IWorkbenchConfigurer</code></td>
            </tr>
            <tr>
                <td>preStartup</td>
                <td>在初始化结束，但是在第一个窗口打开前调用。可以被用来设置一些选项来影响初始打开的编辑器和视图。<br />
                </td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>postStartup</td>
                <td>在所有窗口已经被打开或恢复后，但是在事件循环开始前调用。它可以被用来启动自动处理器，打开提示或其他窗口。<br />
                </td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>preShutdown</td>
                <td>&nbsp;在事件循环结束后，但在任何窗口被关闭前调用。</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>postShutdown</td>
                <td>在关闭Workbench过程中，所有窗口被关闭后调用。它可以被用来存储当前的应用状态和清理任何由initialize创建的东西。</td>
                <td>&nbsp;</td>
            </tr>
        </tbody>
    </table>
    <br />
    <p>表2. WorkbenchAdvisor提供的事件循环钩子 </p>
    <table border="1" height="73" width="695">
        <tbody>
            <tr>
                <th>方法</th>
                <th>描述</th>
                <th>参数</th>
            </tr>
            <tr>
                <td>eventLoopException</td>
                <td>在事件循环中如果有未检测的异常则调用给方法。默认的实现将记录错误信息。</td>
                <td><code>Throwable</code></td>
            </tr>
            <tr>
                <td>eventLoopIdle</td>
                <td>时间循环时什么也不做时调用</td>
                <td><code>Display</code></td>
            </tr>
        </tbody>
    </table>
    <p><br />
    </p>
    <br />
    <p>表3. WorkbenchAdvisor提供的信息获取方法，你可以在子类中覆盖 </p>
    <table border="1">
        <tbody>
            <tr>
                <th>方法</th>
                <th>描述</th>
                <th>参数</th>
            </tr>
            <tr>
                <td>getDefaultPageInput</td>
                <td>返回新的Workbench页面的缺省输入，缺省值是null。</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>getInitialWindowPerspectiveId</td>
                <td>返回新创建的Workbench&nbsp;Window的初始透视图。这个方法必须提供。<br />
                </td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>getMainPreferencePageId</td>
                <td>返回第一个显示的首选参数页。缺省为null意味着首选参数页按字母顺序排序。 </td>
                <td>&nbsp;</td>
            </tr>
        </tbody>
    </table>
    &nbsp;&nbsp;&nbsp;&nbsp;上面的WorkbenchAdvisor事件对大多数应用来说是足够了，但是在某些情况，RCP又提供了两个方法来控制你的应用窗口和控件如何被创建。它们被列在表4，但是我觉得很多程序不需要用到这些。<br />
    <p>表4. WorkbenchAdvisor提供的高级方法 </p>
    <table border="1" height="62" width="700">
        <tbody>
            <tr>
                <th>方法</th>
                <th>描述</th>
                <th>参数</th>
            </tr>
            <tr>
                <td>openWindows</td>
                <td>在启动时打开所有Workbench&nbsp;Window。缺省实现会恢复前面存储的Workbench状态。<br />
                </td>
                <td>&nbsp;</td>
            </tr>
        </tbody>
    </table>
    <br />
    其它的方法在eclipse3.1后都被覆盖了。</li>
    <li><font class="java10" color="#ff0000">ApplicationWorkbenchWindowAdvisor</font><font color="#000000">类</font>：用来控制状态栏，工具栏，标题和窗口的大小等。但它将创建工具栏的任务交给了ApplicationActionBarAdvisor类。</li>
    <li><font color="#ff0000">WorkbenchWindowAdvisor</font>类：查阅Javadoc文档可知，它是配置workbench窗口的公共基类。当窗口被创建时，该类就会被创建，用来配置窗口。用户应该继承该类并覆盖其中的某些方法来满足特定的需求。
    <p>表5. WorkbenchWindowAdvisor提供的生命事件点 </p>
    <table border="1" height="256" width="951">
        <tbody>
            <tr>
                <th>方法</th>
                <th>描述</th>
                <th>参数</th>
            </tr>
            <tr>
                <td>preWindowOpen</td>
                <td>在Workbench&nbsp;Window的构造器中调用。可以使用这个方法来指定窗口是否有菜单栏。然而，窗口的widget还没有创建，因此在这个方法中不能引用它们。<br />
                </td>
                <td><br />
                </td>
            </tr>
            <tr>
                <td>postWindowRestore</td>
                <td>当一个窗口从保存的状态恢复时，但在打开前，被调用。<br />
                </td>
                <td><br />
                </td>
            </tr>
            <tr>
                <td>postWindowCreate</td>
                <td>&nbsp;在窗口从保存状态恢复，或从scratch中创建后，但在打开前，被调用。<br />
                </td>
                <td><br />
                </td>
            </tr>
            <tr>
                <td>openIntro</td>
                <td>在窗口打开前一刻被调用，它用来创建introduction组件（如果有的话）。<br />
                </td>
                <td><br />
                </td>
            </tr>
            <tr>
                <td>postWindowOpen</td>
                <td>紧接着Workbench&nbsp;Window被打开后调用。它被用来组装窗口的widget，例如设置标题或修改它的大小。<br />
                </td>
                <td><br />
                </td>
            </tr>
            <tr>
                <td>preWindowShellClose</td>
                <td>在Workbench&nbsp;Window被关闭前调用（从技术上来说，是在它的shell被关闭前）。这是唯一能够终止关闭动作的方法，所以，它可以用来显示&ldquo;你确定吗&rdquo;这样的对话框。<br />
                </td>
                <td><br />
                </td>
            </tr>
            <tr>
                <td>postWindowClose</td>
                <td>在Workbench&nbsp;Window关闭后调用。它被用来清理任何由preWindowOpen创建的资源。<br />
                </td>
                <td><br />
                </td>
            </tr>
        </tbody>
    </table>
    <p>表5. WorkbenchWindowAdvisor提供高级方法</p>
    <table border="1">
        <tbody>
            <tr>
                <th>方法</th>
                <th>描述</th>
                <th>参数</th>
            </tr>
            <tr>
                <td>createWindowContents</td>
                <td>创建窗口的内容，覆盖该方法来定义用户自己的内容和布局。</td>
                <td><code>Shell</code></td>
            </tr>
            <tr>
                <td>createEmptyWindowContents</td>
                <td>用来创建空页面的窗口，覆盖该方法来改变默认窗口背景</td>
                <td><code>Composite</code></td>
            </tr>
        </tbody>
    </table>
    </li>
    <li><font color="#ff0000">IWorkbenchWindowConfigurer</font>接 口：为配置workbench窗口提供了专门的方法，Window configurer类和要配置的workbench是一对一对应的，用户可以用get/set方法将任意状态和window configurer类相连。注意这些类只供主应用程序使用，该接口不能被实现。</li>
    <li><font color="#ff0000">ApplicationActionBarAdvisor</font>类：继承了ActionBarAdvisor类</li>
    <li><font color="#ff0000">ActionBarAdvisor</font>类：是配置工作台窗口action bars的公用基类。用户应该继承该类并覆盖其中的某些方法来满足特定的需求。
    <p>表7. ActionBarAdvisor提供的可以覆盖的方法</p>
    <table border="1" height="142" width="629">
        <tbody>
            <tr>
                <th>方法</th>
                <th>描述</th>
                <th>参数</th>
            </tr>
            <tr>
                <td>makeActions</td>
                <td>创建actions，供fill方法使用</td>
                <td><code>IWorkbenchWindow</code></td>
            </tr>
            <tr>
                <td>fillMenuBar</td>
                <td>用主菜单填充menubar，添加窗口的主菜单</td>
                <td><code>IMenuManager</code></td>
            </tr>
            <tr>
                <td>fillCoolBar</td>
                <td>用工具栏填充coolbar，添加窗口的工具栏</td>
                <td><code>ICoolBarManager</code></td>
            </tr>
            <tr>
                <td>fillStatusLine</td>
                <td>用状态栏填充statusline，添加窗口的状态栏</td>
                <td><code>IStatusLineManager</code></td>
            </tr>
            <tr>
                <td>isApplicationMenu</td>
                <td>返回是否是你创建的菜单</td>
                <td><code>String</code></td>
            </tr>
        </tbody>
    </table>
    </li>
    <li><font color="#ff0000">Activator</font>类：是一个单例类，用来存储插件的全局信息，也可以有一些其他类会用到的实用方法。</li>
</ol>
          <br/>
          <span style="color:red;">
            <a href="http://luchar.javaeye.com/blog/145650#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/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 03 Dec 2007 17:01:34 +0800</pubDate>
        <link>http://luchar.javaeye.com/blog/145650</link>
        <guid>http://luchar.javaeye.com/blog/145650</guid>
      </item>
      <item>
        <title>GEF原理及实现系列（八、选项板）</title>
        <author>LuChar</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://luchar.javaeye.com">LuChar</a>&nbsp;
          链接：<a href="http://luchar.javaeye.com/blog/145639" style="color:red;">http://luchar.javaeye.com/blog/145639</a>&nbsp;
          发表时间: 2007年12月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          选项板提供了用户选择模型元素，并提供相应的机制把模型和视图加入图形编辑器的能力。<br />
<strong>1.选项板（PaletteRoot）的功能</strong><br />
&nbsp;&nbsp;&nbsp; GEF是一个图形编辑框架，它的主编辑区域是一个图形的视图（类似与JFace的Viewer），另外，用户还可以选择选项板上相应的模型，把选择的模型对应的视图加入到图形编辑区域进行编辑。<br />
&nbsp;&nbsp;&nbsp; 在GEF中，图形编辑器实现类的getPaletteRoot方法将返回一个PaletteRoot对象，用户可以在PaletteRoot中添加模型选 项入口项（ToolEntry）。例如，在选择板中加入一个连线模型的入口，可以加入&ldquo;new ConnectionCreationToolEntry(&quot;连线&quot;, &quot;Create a connection&quot;, null, null, null);&rdquo;，ToolEntry的参数描述了选项板中选项的显示标签、显示图标、提示信息、模型的模板类及模型的创建工厂类等信息。<br />
<strong>2.选项板的实现</strong><br />
&nbsp;&nbsp;&nbsp; 在选项板中创建模型的入口，能添加模型的选择项（ToolEntry）和模型分组项（PaletteDrawer），代码如下：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">package</span><span>&nbsp;com.example.tools;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;java.util.ArrayList;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;java.util.List;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.CombinedTemplateCreationEntry;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.ConnectionCreationToolEntry;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.PaletteContainer;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.PaletteDrawer;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.PaletteGroup;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.PaletteRoot;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.SelectionToolEntry;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.palette.ToolEntry;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;org.eclipse.gef.requests.SimpleFactory;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;com.example.model.Node;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;PaletteFactory&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;PaletteRoot&nbsp;createPalette()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//新建选项板</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PaletteRoot&nbsp;paletteRoot&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;PaletteRoot();&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//添加选项板中的模型选项</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paletteRoot.addAll(createCategories(paletteRoot));&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;paletteRoot;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;List&nbsp;createCategories(PaletteRoot&nbsp;root)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&nbsp;categories&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;ArrayList();&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//添加分组选项</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;categories.add(createControlGroup(root));&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;categories.add(createComponentsDrawer());&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;categories;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;PaletteContainer&nbsp;createControlGroup(PaletteRoot&nbsp;root)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PaletteGroup&nbsp;controlGroup&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;PaletteGroup(</span><span class="string">&quot;Control&nbsp;Group&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&nbsp;entries&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;ArrayList();&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//添加取消模型选择项</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ToolEntry&nbsp;tool&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;SelectionToolEntry();&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.add(tool);&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//设置SelectionToolEntry为默认选项</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&n