﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-freesky-随笔分类-设计模式</title><link>http://www.blogjava.net/freesky/category/22432.html</link><description>自由天空</description><language>zh-cn</language><lastBuildDate>Mon, 14 May 2007 07:16:47 GMT</lastBuildDate><pubDate>Mon, 14 May 2007 07:16:47 GMT</pubDate><ttl>60</ttl><item><title>Java模式设计之模板方法模式 </title><link>http://www.blogjava.net/freesky/archive/2007/05/14/117275.html</link><dc:creator>freesky</dc:creator><author>freesky</author><pubDate>Mon, 14 May 2007 02:40:00 GMT</pubDate><guid>http://www.blogjava.net/freesky/archive/2007/05/14/117275.html</guid><wfw:comment>http://www.blogjava.net/freesky/comments/117275.html</wfw:comment><comments>http://www.blogjava.net/freesky/archive/2007/05/14/117275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freesky/comments/commentRss/117275.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freesky/services/trackbacks/117275.html</trackback:ping><description><![CDATA[<table width="100%">
    <tbody>
        <tr>
            <td>这是一个很简单的模式，却被非常广泛的使用。之所以简单是因为在这个模式中仅仅使用到了继承关系。<br><br>继承关系由于自身的缺陷，被专家们扣上了&#8220;罪恶&#8221;的帽子。&#8220;使用委派关系代替继承关系&#8221;，&#8220;尽量使用接口实现而不是抽象类继承&#8221;等等专家警告，让我们这些菜鸟对继承&#8220;另眼相看&#8221;。<br><br>其实，继承还是有很多自身的优点所在。只是被大家滥用的似乎缺点更加明显了。合理的利用继承关系，还是能对你的系统设计起到很好的作用的。而模板方法模式就是其中的一个使用范例。<br><br><strong>二、定义与结构</strong><br><br>GOF给模板方法（Template Method）模式定义一个操作中的算法的骨架，而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这里的算 法的结构，可以理解为你根据需求设计出来的业务流程。特定的步骤就是指那些可能在内容上存在变数的环节。<br><br>可以看出来，模板方法模式也是为了巧妙解决变化对系统带来的影响而设计的。使用模板方法使系统扩展性增强，最小化了变化对系统的影响。这一点，在下面的举例中可以很明显的看出来。<br><br>来看下这个简单模式的结构吧：<br><br>1) AbstractClass（抽象类）：定义了一到多个的抽象方法，以供具体的子类来实现它们；而且还要实现一个模板方法，来定义一个算法的骨架。该模板方法不仅调用前面的抽象方法，也可以调用其他的操作，只要能完成自身的使命。<br><br>2) ConcreteClass（具体类）：实现父类中的抽象方法以完成算法中与特定子类相关的步骤。<br><br>下面是模板方法模式的结构图。直接把《设计模式》上的图拿过来用下：<br><br>
            <table width="90%" align=center border=0>
                <tbody>
                    <tr>
                        <td>
                        <div align=center><img alt="" src="http://dev.yesky.com/imagelist/05/08/6n18udc5gbnm.jpg"></div>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br><strong>三、举例</strong><br><br>还是在我刚刚分析完源码的JUnit中找个例子吧。JUnit中的TestCase以及它的子类就是一个模板方法模式的例子。在TestCase这个抽 象类中将整个测试的流程设置好了，比如先执行Setup方法初始化测试前提，在运行测试方法，然后再TearDown来取消测试设置。但是你将在 Setup、TearDown里面作些什么呢？鬼才知道呢！！因此，而这些步骤的具体实现都延迟到子类中去，也就是你实现的测试类中。<br><br>来看下相关的源代码吧。<br><br>这是TestCase中，执行测试的模板方法。你可以看到，里面正像前面定义中所说的那样，它制定了&#8220;算法&#8221;的框架——先执行setUp方法来做下初始化，然后执行测试方法，最后执行tearDown释放你得到的资源。<br><br>
            <table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
                <tbody>
                    <tr>
                        <td>public void runBare() throws Throwable {<br>setUp();<br><br>try {<br>runTest();<br>}<br><br>finally {<br>tearDown();<br>}<br>}</td>
                    </tr>
                </tbody>
            </table>
            <br>这就是上面使用的两个方法。与定义中不同的是，这两个方法并没有被实现为抽象方法，而是两个空的无为方法（被称为钩子方法）。这是因为在测试中，我们并 不是必须要让测试程序使用这两个方法来初始化和释放资源的。如果是抽象方法，则子类们必须给它一个实现，不管用到用不到。这显然是不合理的。使用钩子方 法，则你在需要的时候，可以在子类中重写这些方法。<br><br>
            <table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
                <tbody>
                    <tr>
                        <td>protected void setUp() throws Exception {}<br>protected void tearDown() throws Exception {}</td>
                    </tr>
                </tbody>
            </table>
            <br>四、适用情况<br><br>根据上面对定义的分析，以及例子的说明，可以看出模板方法适用于以下情况：<br><br>1) 一次性实现一个算法的不变的部分，并将可变的行为留给子类来实现。<br><br>2) 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。其实这可以说是一种好的编码习惯了。<br><br>3) 控制子类扩展。模板方法只在特定点调用操作，这样就只允许在这些点进行扩展。比如上面runBare（）方法就只在runTest前面适用setUp方 法。如果你不愿子类来修改你的模板方法定义的框架，你可以采用两种方式来做：一是在API中不体现出你的模板方法；二、将你的模板方法置为final就可 以了。<br><br>可以看出，使用模板方法模式可以将代码的公共行为提取出来，达到复用的目的。而且，在模板方法模式中，是由父类的模板方法来控制子类中的具体实现。这样你在实现子类的时候，根本不需要对业务流程有太多的了解。</td>
        </tr>
    </tbody>
</table>
<p><br>&nbsp;</p>
<p>转载：<a href="http://fly-net-cn.javaeye.com/blog/78611">http://fly-net-cn.javaeye.com/blog/78611</a></p>
<img src ="http://www.blogjava.net/freesky/aggbug/117275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freesky/" target="_blank">freesky</a> 2007-05-14 10:40 <a href="http://www.blogjava.net/freesky/archive/2007/05/14/117275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java设计模式之策略模式</title><link>http://www.blogjava.net/freesky/archive/2007/05/14/117266.html</link><dc:creator>freesky</dc:creator><author>freesky</author><pubDate>Mon, 14 May 2007 02:28:00 GMT</pubDate><guid>http://www.blogjava.net/freesky/archive/2007/05/14/117266.html</guid><wfw:comment>http://www.blogjava.net/freesky/comments/117266.html</wfw:comment><comments>http://www.blogjava.net/freesky/archive/2007/05/14/117266.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freesky/comments/commentRss/117266.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freesky/services/trackbacks/117266.html</trackback:ping><description><![CDATA[<p>策略模式（Strategy Pattern）中体现了两个非常基本的面向对象设计的基本原则：封装变化的概念；编程中使用接口，而不是对接口实现。策略模式的定义如下： </p>
<p>定义一组算法，将每个算法都封装起来，并且使它们之间可以互换。策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。 </p>
<p>策略模式使开发人员能够开发出由许多可替换的部分组成的软件，并且各个部分之间是弱连接的关系。弱连接的特性使软件具有更强的可扩展性，易于维护；更重要的是，它大大提高了软件的可重用性。 </p>
<p>为了说明策略模式，我们将首先讨论一下在Swing中是如何利用策略模式来绘制组件边界的，然后讨论在Swing中使用策略模式带来的好处，最后讨论如何在软件中实现策略模式。 </p>
<center><font color=#000099><strong>Swing边框</strong></font></center>
<p>对所有的Swing组件，例如按钮、列表单等，都还可以绘制边框。在Swing中提供了各种 边框类型，例如bevel、etched、line、titled等。Swing组件的边框是通过JComponent类来绘制的，该类是所有Swing 组件的基类，实现了所有Swing组件公共的功能。在JComponent中有一个paintBorder()方法，该方法为组件绘制边框。Swing的 开发人员可以象下面的例子中所示那样来绘制边框： </p>
<p><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code bgColor=#e6e6e6>
            <pre><ccid_code>// 一段实现paintBorder（）方法代码<br>protected void paintBorder(Graphics g) {<br>   switch(getBorderType()) {<br>      case LINE_BORDER:   paintLineBorder(g);<br>                          break;<br>      case ETCHED_BORDER: paintEtchedBorder(g);<br>                          break;<br>      case TITLED_BORDER: paintTitledBorder(g);<br>                          break;<br>      ...<br>   }<br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>请注意上面的代码只是一种假设，事实上Swing的开发人员并没有这样实现 paintBorder（）方法。在上面的代码中，在JComponent中绘制边框的代码被直接写入了paintBorder（）方法中，这意味着 JComponent和绘制边框的功能被紧密地结合在了一起。很自然地大家会联想到如果需要实现一种新的边框类型，开发人员必须修改至少三处代码：首先增 加一个常量，该常量代表新添加的边框的类型值；其次需要在Switch语句中增加一个case语句；最后开发人员需要实现paintXXXBorder （）方法，其中XXX代表新边框的名称。 </p>
<p>很显然要扩展上面paintBorder()方法的功能是一件很困难的事情，不仅 仅是因为开发人员需要增加一种新的边框类型，更麻烦的是开发人员很难修改JComponent类。JComponent类已经被编译到了Swing的开发 工具中，如果开发人员想修改它的话，必须获得Swing的源代码，修改后重新编译Swing。同时在用户的计算机上与需要使用新编译的Swing API。另外所有的Swing组件都可以使用开发人员新添加的边框类型。有可能开发人员只希望新的边框被某些组件使用，但是现在开发人员无法对使用该边框 的组件进行限制。 </p>
<p>开发人员有更好的实现方法吗？答案就是策略模式。通过策略模式，可以将 JComponent和实现绘制边框的代码分离开来，这样开发人员在增加或修改绘制边框的代码使就不需要修改JComponent的代码。通过应用策略模 式，开发人员将变化的概念（在这个例子中是绘制边框）封装起来，然后通过一个Border接口，使程序能够重用绘制边框的功能。下面让我们来看 JComponent是如何利用策略模式来实现绘制边框的功能的： </p>
<p><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code bgColor=#e6e6e6>
            <pre><ccid_code>// Swing中paintBorder()方法的源代码<br>protected void paintBorder(Graphics g) {<br>   Border border = getBorder();<br>   if (border != null) {<br>      border.paintBorder(this, g, 0, 0, getWidth(), getHeight());<br>   }<br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>上面的paintBorder()方法通过一个border对象绘制了组件的边框。 这样border对象替代了前一个例子中的JComponent封装了边框绘制的功能。我们还应该注意到JComponent将一个对自己的引用传递给了 Border.paintBorder（）方法，这是因为Border的实例必须知道它对应的组件的信息，这种方式通常被称为委托。通过这种方式，一个对 象可以将功能委托给另一个对象来实现。 </p>
<p>在JComponent类中引用了一个Border对象，通过JComponent.getBorder（）方法可以获得该Border对象。下面的代码演示了如何设定和获得Border对象： </p>
<p><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code bgColor=#e6e6e6>
            <pre><ccid_code>...<br>private Border border;<br>...<br>public void setBorder(Border border) {<br>   Border oldBorder = this.border;<br>   this.border = border;<br>   firePropertyChange("border", oldBorder, border);<br>   if (border != oldBorder) {<br>      if (border == null || oldBorder == null || !(border.getBorderInsets(this).<br>                                    equals(oldBorder.getBorderInsets(this)))) {<br>         revalidate();<br>      }       <br>      repaint();<br>   }<br>}<br>...<br>public Border getBorder() {<br>   return border;<br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>当开发人员通过JComponent.setBorder（）方法设定了一个组件的 边框后，JComponent类发出一个属性更新事件。如果新的边框和以前的边框不同的话，setBorder（）方法就重新绘制边框。 getBorder（）方法仅仅返回对Border对象的引用。图1显示了Border的类结构图： </p>
<center><img alt="" src="http://industry.ccidnet.com/col/attachment/2003/2/99506.jpg"></center>
<center>图1 Border的类结构图</center>
<p>通过类结构图我们可以看到，JComponent类中保存了一个对Border对象的引用。由于Border是一个接口，Swing组件可以使用任何一个实现了Border接口的类。 </p>
<p>现在我们已经知道了JComponent是如何利用策略模式来绘制组件的边框的。下面让我们通过实现一个新的边框类型来测试一下它的可扩展性。 </p>
<center><font color=#000099><strong>实现一个新的边框类型</strong></font></center>
<p>图2中是一个有三个JPanel对象的小程序，每个JPanel对象有各自不同的边框，每个边框对应一个HandleBorder实例。 </p>
<center><img alt="" src="http://industry.ccidnet.com/col/attachment/2003/2/99507.jpg"></center>
<center>图2 新的边框类型</center>
<p><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code bgColor=#e6e6e6>
            <pre><ccid_code>// HandleBorder.java<br>import java.awt.*;<br>import javax.swing.*;<br>import javax.swing.border.*;<br>public class HandleBorder extends AbstractBorder {<br>   protected Color lineColor;<br>   protected int thick;<br>   public HandleBorder() {<br>      this(Color.black, 6);<br>   }<br>   public HandleBorder(Color lineColor, int thick) {<br>      this.lineColor = lineColor;<br>      this.thick = thick;<br>   }<br>   public void paintBorder(Component component, <br>                                  Graphics g, int x, int y, int w, int h) {<br>      Graphics copy = g.create();<br>      if(copy != null) {<br>         try {<br>            copy.translate(x,y);<br>            paintRectangle(component,copy,w,h);<br>            paintHandles(component,copy,w,h);<br>         }<br>         finally {<br>            copy.dispose();<br>         }<br>      }<br>   }<br>   public Insets getBorderInsets() {<br>      return new Insets(thick,thick,thick,thick);<br>   }<br>   protected void paintRectangle(Component c, Graphics g,<br>                           int w, int h) {<br>      g.setColor(lineColor);<br>      g.drawRect(thick/2,thick/2,w-thick-1,h-thick-1);<br>   }<br>   protected void paintHandles(Component c, Graphics g,<br>                           int w, int h) {<br>      g.setColor(lineColor);<br>      g.fillRect(0,0,thick,thick); <br>      g.fillRect(w-thick,0,thick,thick); <br>      g.fillRect(0,h-thick,thick,thick); <br>      g.fillRect(w-thick,h-thick,thick,thick); <br>      g.fillRect(w/2-thick/2,0,thick,thick); <br>      g.fillRect(0,h/2-thick/2,thick,thick); <br>      g.fillRect(w/2-thick/2,h-thick,thick,thick); <br>      g.fillRect(w-thick,h/2-thick/2,thick,thick); <br>   }   <br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>HandleBorder类继承了 javax.swing.border.AbstractBorder类并重写了paintBorder（）和getBorderInsets（）。 HandleBorder是如何实现的其实并不重要，重要的是由于Swing使用了策略模型，开发人员能够很方便地增加新的边框类型。下面的代码显示了如 何使用HandleBorder类。在这个例子中创建了三个JPanel对象，并对每个JPanel对象设定一个HandleBorder实例作为边框。 </p>
<p><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code bgColor=#e6e6e6>
            <pre><ccid_code>// Test.java<br>import javax.swing.*;<br>import javax.swing.border.*;<br>import java.awt.*;<br>import java.awt.event.*;<br>public class Test extends JFrame {<br>   public static void main(String[] args) {<br>      JFrame frame = new Test();<br>      frame.setBounds(100, 100, 500, 200);<br>      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);<br>      frame.show();<br>   }<br>   public Test() {<br>      super("实现一个新的边框类型");<br>      Container contentPane = getContentPane();<br>      JPanel[] panels = { new JPanel(), <br>                     new JPanel(), new JPanel() };<br>      Border[] borders = { new HandleBorder(),<br>                     new HandleBorder(Color.red, 8),<br>                     new HandleBorder(Color.blue, 10) };<br>      contentPane.setLayout(<br>               new FlowLayout(FlowLayout.CENTER,20,20));<br>      for(int i=0; i &lt; panels.length; ++i) {<br>         panels[i].setPreferredSize(new Dimension(100,100));<br>         panels[i].setBorder(borders[i]);<br>         contentPane.add(panels[i]);<br>      }<br>   }<br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>还记得在上面的例子中曾提到在有些情况下，对组件的引用会作为参数传递给 Border.paintBorder（）方法。虽然上面的HandleBorder类没有保存对组件的引用，但是有些情况下Border接口的实现类会 使用到对组件的引用并从中获得关于组件的信息。例如在EtchedBorder中，paintBorder（）方法通过对组件的引用获得它对应的组件的阴 影和高光色： </p>
<p><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code bgColor=#e6e6e6>
            <pre><ccid_code>// 下面的代码截取自javax.swing.border.EtchedBorder<br>public void paintBorder(Component component, Graphics g, int x, int y, <br>                         int width, int height) {<br>   int w = width;<br>   int h = height;<br>   g.translate(x, y);<br>   g.setColor(etchType == LOWERED? getShadowColor(component) : <br>getHighlightColor(component));<br>   g.drawRect(0, 0, w-2, h-2);<br>   g.setColor(etchType == LOWERED? getHighlightColor(component) : <br>getShadowColor(component));<br>   g.drawLine(1, h-3, 1, 1);<br>   g.drawLine(1, 1, w-3, 1);<br>   g.drawLine(0, h-1, w-1, h-1);<br>   g.drawLine(w-1, h-1, w-1, 0);<br>   g.translate(-x, -y);<br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<center><font color=#000099><strong>如何实现策略模型</strong></font></center>
<p>通过以下步骤，开发人员可以很容易地在软件中实现策略模型： </p>
<p>1．对策略对象定义一个公共接口。 </p>
<p>2．编写策略类，该类实现了上面的公共接口。 </p>
<p>3．在使用策略对象的类中保存一个对策略对象的引用。 </p>
<p>4．在使用策略对象的类中，实现对策略对象的set和get方法。 </p>
<p>在Swing边框的例子中，公共接口是javax.swing.Border。策略类是LineBorder、EtchedBorder、HandleBorder等。而使用策略对象的类是JComponent。 </p>
<p><br>&nbsp;</p>
<p>转载：<a href="http://fly-net-cn.javaeye.com/blog/78615">http://fly-net-cn.javaeye.com/blog/78615</a></p>
<img src ="http://www.blogjava.net/freesky/aggbug/117266.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freesky/" target="_blank">freesky</a> 2007-05-14 10:28 <a href="http://www.blogjava.net/freesky/archive/2007/05/14/117266.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>