﻿<?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-细心!用心!耐心!-文章分类-Creational 模式</title><link>http://www.blogjava.net/jesson2005/category/21662.html</link><description>吾非文人，乃市井一俗人也，读百卷书，跨江河千里，故申城一游； 
一两滴辛酸，三四年学业，五六点粗墨，七八笔买卖，九十道人情。</description><language>zh-cn</language><lastBuildDate>Thu, 19 Apr 2007 13:18:06 GMT</lastBuildDate><pubDate>Thu, 19 Apr 2007 13:18:06 GMT</pubDate><ttl>60</ttl><item><title>Design Pattern: Prototype 模式</title><link>http://www.blogjava.net/jesson2005/articles/111168.html</link><dc:creator>张金鹏</dc:creator><author>张金鹏</author><pubDate>Tue, 17 Apr 2007 02:35:00 GMT</pubDate><guid>http://www.blogjava.net/jesson2005/articles/111168.html</guid><wfw:comment>http://www.blogjava.net/jesson2005/comments/111168.html</wfw:comment><comments>http://www.blogjava.net/jesson2005/articles/111168.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jesson2005/comments/commentRss/111168.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jesson2005/services/trackbacks/111168.html</trackback:ping><description><![CDATA[您從圖書館的期刊從發現了幾篇您感興趣的文章，由於這是圖書館的書，您不可以直接在書中作記號或寫字，所以您將當中您所感興趣的幾個主題影印出來，這下子您就可在影印的文章上畫記重點。<br><br>Prototype模式的作用有些類似上面的描述，您在父類別中定義一個clone()方法，而在子類別中重新定義它，當客戶端對於所產生的物件有興趣並想加以利用，而您又不想破壞原來的物件，您可以產生一個物件的複本給它。<br><br>Prototype具有展示的意味，就像是展覽會上的原型車款，當您對某個車款感興趣時，您可以購買相同款示的車，而不是車展上的車。<br><br>在軟體設計上的例子會更清楚的說明為何要進行物件複製，假設您要設計一個室內設計軟體，軟體中有一個展示家具的工具列，您只要點選工具列就可以產生一個家具複本，例如一張椅子或桌子，您可以拖曳這個複製的物件至設計圖中，隨時改變它的位置、顏色等等，當您改變設計圖中的物件時，工具列上的原型工具列是不會跟著一起改變的，這個道理是無需解釋的。<br><br>下面的 UML 類別圖表示了上述的簡單概念： <br>
<div style="TEXT-ALIGN: center"><img title=Prototype style="WIDTH: 558px; HEIGHT: 266px" alt=Prototype src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/protoType-1.jpg"><br><br>
<div style="TEXT-ALIGN: left">Prototype模式的重點在於clone()，它負責複製物件本身並傳回，但這個clone()本身在實作上存在一些困難，尤其是當物件本身又繼承另一個物件時，如何確保複製的物件完整無誤，在不同的程式語言中有不同的作法。<br><br>在Java中的作法是透過實作一個Cloneable介面，它只是一個聲明的介面，並無規定任何實作的方法，您的目的是改寫Object的clone ()方法，使其具備有複製物件的功能，這個方面建議您參考：<a href="http://www.javaworld.com/javaworld/jw-01-1999/jw-01-object.html">How to avoid traps and correctly override methods from java.lang.Object</a>。<br><br>用一個簡單的例子來實作上圖中的結構，這個例子利用了Java語言本身的clone特性：</div>
</div>
<ul>
    <li>AbstractFurniture.java </li>
</ul>
<pre>public abstract class AbstractFurniture <br>                             implements Cloneable {<br>    public abstract void draw();<br>    <br>    // 在Design Pattern上，以下的clone是抽象未實作的<br>    // 實際上在Java中class都繼承自Object<br>    // 所以在這邊我們直接重新定義clone() <br>    // 這是為了符合Java現行的clone機制<br>    protected Object clone() throws CloneNotSupportedException { <br>        return super.clone(); <br>    }<br>}</pre>
<br>CircleTable與SquareTable繼承了AbstractFurniture，並實作clone方法，用於傳回本身的複製品：<br>
<ul>
    <li>CircleTable.java </li>
</ul>
<pre>import java.awt.*;<br><br>public class CircleTable extends AbstractFurniture {<br>    protected Point center;    <br>    <br>    public void setCenter(Point center) {<br>        this.center = center;<br>    }<br>    <br>    protected Object clone () <br>                     throws CloneNotSupportedException { <br>        Object o = super.clone(); <br>        if(this.center != null) {<br>            ((CircleTable) o).center = (Point) center.clone();<br>        }<br>        <br>        return o; <br>    } <br><br>    public void draw() { <br>        System.out.println("\t圓桌\t中心：(" + center.getX() <br>                            + ", " + center.getY()+ ")");<br>    } <br>}</pre>
<br>
<ul>
    <li>SquareTable.java </li>
</ul>
<pre>import java.awt.*;<br><br>public class SquareTable extends AbstractFurniture {<br>    protected Rectangle rectangle;    <br>    <br>    public void setRectangle(Rectangle rectangle) {<br>        this.rectangle = rectangle;<br>    }<br>    <br>    protected Object clone () <br>                      throws CloneNotSupportedException { <br>        Object o = super.clone(); <br>        if(this.rectangle != null) { <br>            ((SquareTable) o).rectangle = (Rectangle) rectangle.clone();<br>        }<br>        <br>        return o; <br>    } <br><br>    public void draw() { <br>        System.out.print("\t方桌\t位置：(" + rectangle.getX() <br>                            + ", " + rectangle.getY()+ ")");<br>        System.out.println(" / 寬高：(" + <br>                         rectangle.getWidth() <br>                + ", " + rectangle.getHeight()+ ")");<br>    }<br>}</pre>
<br>House是個虛擬的房屋物件，從Prototype複製出來的物件加入至House中：<br>
<ul>
    <li>House.java </li>
</ul>
<pre>import java.util.*;<br><br>public class House { <br>    private Vector vector;<br><br>    public House() { <br>        vector = new Vector(); <br>    }<br><br>    public void addFurniture(AbstractFurniture furniture) { <br>        vector.addElement(furniture); <br>        <br>        System.out.println("現有家具....");<br>        <br>        Enumeration enumeration = vector.elements();<br>        while(enumeration.hasMoreElements()) { <br>             AbstractFurniture f = <br>                 (AbstractFurniture) enumeration.nextElement(); <br>             f.draw(); <br>        } <br>        System.out.println(); <br>    } <br>}</pre>
<br>再來是應用程式本身：<br>
<ul>
    <li>Application.java </li>
</ul>
<pre>import java.awt.*;<br><br>public class Application {<br>    private AbstractFurniture circleTablePrototype;<br>    <br>    public void setCircleTablePrototype(<br>                   AbstractFurniture circleTablePrototype) {<br>        this.circleTablePrototype = circleTablePrototype;<br>    }<br>    <br>    public void runAppExample() throws Exception {<br>        House house = new House(); <br>        CircleTable circleTable = null;<br><br>        // 從工具列選擇一個家具加入房子中<br>        circleTable =<br>            (CircleTable) circleTablePrototype.clone();<br>        circleTable.setCenter(new Point(10, 10));<br>        house.addFurniture(circleTable); <br>        <br>        // 從工具列選擇一個家具加入房子中<br>        circleTable = <br>            (CircleTable) circleTablePrototype.clone();<br>        circleTable.setCenter(new Point(20, 30));<br>        house.addFurniture(circleTable); <br>    }<br>    <br>    public static void main(String[] args) throws Exception {<br>        Application application = new Application();<br>        application.setCircleTablePrototype(<br>                            new CircleTable());<br>        application.runAppExample();<br>    }<br>}</pre>
<br>Java中的clone()方法是繼承自Object，AbstractFurniture的子類別則override這個clone()方法，以複製其本身並傳回。<br><br>下圖為Prototype模式的類別結構圖： <br>
<div style="TEXT-ALIGN: center"><img title=Prototype style="WIDTH: 473px; HEIGHT: 239px" alt=Prototype src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/protoType-2.jpg"><br>
<div style="TEXT-ALIGN: left">在 Gof 的設計模式書中給出一個原型模式的應用：一個通用的圖型編輯器 Framework。在這個 Framework中有一個工具列，您可以在上面選擇音樂符號以加入樂譜中，並可以隨時調整音樂符號的位置等等。<br><br>圖型編輯器Framework是通用的，然而它並不知道這些音樂符號的型態，有人或許會想到繼承圖型編輯器Framework來為每個音樂符號設計一個框架子類別，但由於音樂符號的種類很多，這會產生相當多的子類別，為了避免這種情況，可以透過Prototype模式來減少子類別的數目，可以設計出以下的結構：<br>
<div style="TEXT-ALIGN: center"><img title=Prototype style="WIDTH: 472px; HEIGHT: 317px" alt=Prototype src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/protoType-3.jpg"><br><br></div>
</div>
</div>
依照這個結構，圖型編輯器的Framework可以獨立於要套用的特定類別之外，雖然不知道被複製傳回的對象型態是什麼，但總可以按照 Graphics所定義的介面來操作這些物件。<br>
<img src ="http://www.blogjava.net/jesson2005/aggbug/111168.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jesson2005/" target="_blank">张金鹏</a> 2007-04-17 10:35 <a href="http://www.blogjava.net/jesson2005/articles/111168.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Pattern: Builder 模式</title><link>http://www.blogjava.net/jesson2005/articles/111169.html</link><dc:creator>张金鹏</dc:creator><author>张金鹏</author><pubDate>Tue, 17 Apr 2007 02:35:00 GMT</pubDate><guid>http://www.blogjava.net/jesson2005/articles/111169.html</guid><wfw:comment>http://www.blogjava.net/jesson2005/comments/111169.html</wfw:comment><comments>http://www.blogjava.net/jesson2005/articles/111169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jesson2005/comments/commentRss/111169.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jesson2005/services/trackbacks/111169.html</trackback:ping><description><![CDATA[您想要建立一個迷宮產生程式，迷宮使用二維陣列來定義，0表示道路，1表示牆，2表示寶物，根據所定義的二維迷宮陣列，您想要程式自動產生各種不同材質的迷宮，例如磚牆迷宮，鑽石迷宮等等。<br><br>您可以在程式中定義兩個角色，一個是指導迷宮建立的Director角色，一個是按照指導者指示建立迷宮的Builder角色，Director根據定義的迷宮陣列來指導Builder，只要更換Builder，就可以完成不同材質的迷宮。<br><br>可以使用下面的UML 類別圖來表示上述的概念：<br>
<div style="TEXT-ALIGN: center"><img title=Builder style="WIDTH: 530px; HEIGHT: 515px" alt=Builder src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/builder-1.jpg"><br></div>
實際上的程式設計如下：<br>
<ul>
    <li>MazeDirector.java </li>
</ul>
<pre>public class MazeDirector {<br>    private int[][] maze;<br>    private IMazeBuilder mazeBuilder;<br><br>    public void setMaze(int[][] maze) {<br>        this.maze = maze;<br>    }<br>    <br>    public void setMazeBuilder(IMazeBuilder mazeBuilder) {<br>        this.mazeBuilder = mazeBuilder;<br>    }<br>    <br>    public void buildMaze() {<br>        for(int i = 0; i &lt; maze.length; i++) {<br>            for(int j = 0; j &lt; maze[i].length; j++) {<br>                // 由於mazeBuilder是IMazeBuilder型態<br>                // 所以無論Builder實例為何，這邊的程式都無需變動<br>               &nbsp;switch (maze[i][j]) {<br>                    case 0:<br>                        mazeBuilder.createRoadBlock();<br>                        break;<br>                    case 1:<br>                        mazeBuilder.createWallBlock();<br>                        break;<br>                    case 2:<br>                        mazeBuilder.createTreasureBlock();<br>                        break;<br>                    default:<br>                        System.out.println("undefined");<br>                }<br>            }<br>            mazeBuilder.nextRow();    <br>        }<br>    }<br>} <br></pre>
<br>
<ul>
    <li>IMazeBuilder.java </li>
</ul>
<pre>public interface IMazeBuilder {<br>    public void createRoadBlock();<br>    public void createWallBlock();<br>    public void createTreasureBlock();<br>    public void nextRow();<br>} <br></pre>
<br>
<ul>
    <li>SoliderMazeBuilder.java </li>
</ul>
<pre>public class SolidMazeBuilder implements IMazeBuilder {<br>    public void createWallBlock() {<br>        System.out.print("█");<br>    }<br>    <br>    public void createRoadBlock() {<br>        System.out.print("　");<br>    }<br>    <br>    public void createTreasureBlock() {<br>        System.out.print("$ ");<br>    }<br>    <br>    public void nextRow() {<br>        System.out.println();<br>    }<br>} <br></pre>
<br>
<ul>
    <li>DiamondMazeBuilder.java </li>
</ul>
<pre>public class DiamondMazeBuilder implements IMazeBuilder {<br>    public void createWallBlock() {<br>        System.out.print("◇");<br>    }<br>    <br>    public void createRoadBlock() {<br>        System.out.print("　");<br>    }<br>    <br>    public void createTreasureBlock() {<br>        System.out.print("* ");<br>    }<br>    <br>    public void nextRow() {<br>        System.out.println();<br>    }    <br>}  <br></pre>
<br>使用下面的程式來測試一下，它將產生兩個迷宮圖形：<br>
<pre>public class Main {<br>    public static void main(String[] args) {<br>        int[][] maze = {{1, 1, 1, 1, 1, 1, 1}, <br>                        {1, 0, 0, 0, 0, 2, 1}, <br>                        {1, 0, 1, 0, 1, 0, 1}, <br>                        {1, 0, 2, 1, 0, 1, 1}, <br>                        {1, 1, 0, 1, 0, 1, 1}, <br>                        {1, 0, 0, 2, 0, 0, 1}, <br>                        {1, 1, 1, 1, 1, 1, 1}};<br>        <br>        MazeDirector mazeDirector = new MazeDirector();<br>        mazeDirector.setMaze(maze);<br>        <br>        System.out.println("Build SolidMaze....");<br>        mazeDirector.setMazeBuilder(new SolidMazeBuilder());<br>        mazeDirector.buildMaze();<br>        <br>        System.out.println("Build DiamondMaze....");<br>        <br>        mazeDirector.setMazeBuilder(<br>                       new DiamondMazeBuilder());<br>        mazeDirector.buildMaze();<br>    }<br>} </pre>
<br>
<div style="TEXT-ALIGN: center"><img title=Builder style="WIDTH: 492px; HEIGHT: 181px" alt=Builder src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/builder-2.jpg"><br></div>
<br>在迷宮例子中並沒有產生或返回產品物件，這視您的需求而定，迷宮例子只是將結果輸出至主控台，您也可以設計一個產品物件，或是將結果直接輸出為文件。<br><br>在<a href="http://caterpillar.onlyfun.net/Gossip/DesignPattern/GoF.htm"> Gof </a>中有給出了一個不錯的例子，以設計文件剖析器為例，該剖析器可以將文件轉換為其它的格式，以DOC文件剖析器為例好了，假設希望析剖器可以將DOC文件轉換為RTF或是PDF文件，可以如下設計結構：<br>
<div style="TEXT-ALIGN: center"><img title=Builder style="WIDTH: 482px; HEIGHT: 256px" alt=Builder src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/builder-3.jpg"><br></div>
<br>簡單來說，建築者模式適用的場合，在於使得您可以依賴抽象的建築藍圖，而實際建造時可以使用不同的實例，這是其之所以命為Builder的原因.
<img src ="http://www.blogjava.net/jesson2005/aggbug/111169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jesson2005/" target="_blank">张金鹏</a> 2007-04-17 10:35 <a href="http://www.blogjava.net/jesson2005/articles/111169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Pattern: Singleton 模式</title><link>http://www.blogjava.net/jesson2005/articles/111166.html</link><dc:creator>张金鹏</dc:creator><author>张金鹏</author><pubDate>Tue, 17 Apr 2007 02:33:00 GMT</pubDate><guid>http://www.blogjava.net/jesson2005/articles/111166.html</guid><wfw:comment>http://www.blogjava.net/jesson2005/comments/111166.html</wfw:comment><comments>http://www.blogjava.net/jesson2005/articles/111166.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jesson2005/comments/commentRss/111166.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jesson2005/services/trackbacks/111166.html</trackback:ping><description><![CDATA[Singleton的英文意義是獨身，也就是只有一個人，應用在物件導向語言上，通常翻譯作單例：單一個實例（Instance）。<br><br>很多時候，您會需要Singleton模式，例如印表機管理，您希望程式中只能有一個Print Spooler，以避免兩個列印動作同時輸入至印表機中；例如資料庫管理，因為建立連接（Connection）物件會耗用資源，您希望程式中只能有一個連接物件，所有其它的程式都透過這個物件來連接資料庫，以避免連接物件的重複開啟造成資源的耗用；例如系統程式屬性檔的讀取，您使用單一個物件來讀取屬性內容，而程式的其它部份都向這個物件要求屬性資料，而不是自行讀取屬性資料。<br><br>以印表機設計為例，有的設計人員會採取全域變數的方式來建立實例，並在程式中隨機取用這個實例，Java雖然不支援全域變數，但透過將物件包裝在一個類別之中，也有人會採用這樣的寫法： <br>
<div style="MARGIN-LEFT: 40px">&nbsp;<span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class PrintSpooler { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public PrintSpooler() { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // .... </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public Connection getSpooler(){ </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .... </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">} </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;public class GlobalObject { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private PrintSpooler printSpooler; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public GlobalObject () { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printSpooler = new PrintSpooler(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public void getPrintSpooler() { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return printSpooler; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;}<br></span><br></div>
無論全域變數或是以上的例子，都無法保證只產生唯一個實例，您也許會注意不犯這個錯誤，但與您共同工作的夥伴也許會直覺的使用建構方法來產生一個 PrintSpooler實例。<br><br>Singleton模式可以保證一個類別只有一個實例，並提供一個訪問（visit）這個實例的方法。<br><br>一個Singleton實作即為Java中的java.lang.Runtime類別，每個Java程式執行時都有一個唯一的Runtime物件，可以透過它提供的靜態方法getRuntime()方法來取得這個物件，例如： <br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Runtime runtime = Runtime.getRuntime();</span><br></div>
<br>取得Runtime物件之後，您可以透過它進行一些外部命令的執行、進行垃圾處理等等指令，您可以開啟Runtime.java類別，開頭的幾行是這樣寫的：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Runtime { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Runtime currentRuntime = new Runtime(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static Runtime getRuntime() { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return currentRuntime; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp; /** Don't let anyone else instantiate this class */ </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp; private Runtime() {} </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; // 以下略 </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
&nbsp;<br>上面結構即採用Singleton模式設計，其結構使用 UML 來表即如下所示：<br>
<div style="TEXT-ALIGN: center"><img title=Singleton style="WIDTH: 342px; HEIGHT: 138px" alt=Singleton src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/singleton-1.jpg"><br></div>
如上所示的，Java使用 <a href="http://caterpillar.onlyfun.net/Gossip/DesignPattern/SimpleFactory.htm">靜態工廠</a> 來取得Runtime物件，其中Runtime的建構函式被宣告為private，這樣可以阻止其他人使用建構方法來建立實例；使用更一般化的表示單例的UML結構，如下圖所示： <br>
<div style="TEXT-ALIGN: center"><img title=Singleton style="WIDTH: 363px; HEIGHT: 151px" alt=Singleton src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/singleton-2.jpg"><br></div>
<br>有幾個實作上面結構的方法，可以在第一次需要實例時再建立物件，也就是採用所謂的Lazy Initialization：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Singleton { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Singleton instance = null; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private Singleton() { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // .... </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static Singleton getInstance() { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (instance == null) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = new Singleton(); <br>&nbsp; &nbsp; &nbsp; &nbsp; }<br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"></span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instance; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; // .. 其它實作 </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
<br>上面的實作適用於單執行緒的程式，在多執行緒的程式下，以下的寫法在多個執行緒的競爭資源下，將仍有可能產生兩個以上的實例，例如下面的情況：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Thread1: if(instance == null) // true</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Thread2: if(instance == null) // true</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Thread1: instance = new Singleton(); // 產生一個實例</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Thread2: instance = new Singleton(); // 又產生一個實例</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Thread1: return instance; // 回傳一個實例</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Thread2: return instance; // 又回傳一個實例</span><br></div>
<br>在多執行緒的環境下，為了避免資源同時競爭而導致如上產生多個實例的情況，加上同步（synchronized）機制：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Singleton {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Singleton instance = null;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private Singleton(){}</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; synchronized static public Singleton getInstance() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (instance == null) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = new Singleton();<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"></span><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instance;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
&nbsp;<br>不過這種簡單的寫法不適合用於像伺服器這種服務很多執行緒的程式上，同步機制會造成相當的效能低落，為了顧及Singleton、Lazy Initialization與效能問題，因而有了Double-check Locking的模式：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Singleton {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Singleton instance = null;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private Singleton(){}</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static Singleton getInstance() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (instance == null){</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(Singleton.class){</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(instance == null) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = new Singleton();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instance;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
&nbsp;<br>Java中Runtime類別的作法就簡單多了，它捨棄了Lazy Initialization，如果您的實例初始化不是很久的話，可以用這種方式：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Singleton { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Singleton instance = new Singleton(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private Singleton() { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // .... </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static Singleton getInstance() { </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instance; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; } </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; // 其它實作 </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
&nbsp;<br>Singleton本身的觀念簡單但應用很廣，因而很多時候必須對實際環境作一些考量與調整，建議您也看看有關於Singleton的這篇 <a href="http://www.jsptw.com/jute/post/view?bid=25&amp;id=3939&amp;sty=1&amp;tpg=2&amp;age=0">討論</a>。<br>
<img src ="http://www.blogjava.net/jesson2005/aggbug/111166.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jesson2005/" target="_blank">张金鹏</a> 2007-04-17 10:33 <a href="http://www.blogjava.net/jesson2005/articles/111166.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Pattern: Registry of Singleton 模式</title><link>http://www.blogjava.net/jesson2005/articles/111167.html</link><dc:creator>张金鹏</dc:creator><author>张金鹏</author><pubDate>Tue, 17 Apr 2007 02:33:00 GMT</pubDate><guid>http://www.blogjava.net/jesson2005/articles/111167.html</guid><wfw:comment>http://www.blogjava.net/jesson2005/comments/111167.html</wfw:comment><comments>http://www.blogjava.net/jesson2005/articles/111167.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jesson2005/comments/commentRss/111167.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jesson2005/services/trackbacks/111167.html</trackback:ping><description><![CDATA[考慮使用 <a href="http://caterpillar.onlyfun.net/Gossip/DesignPattern/SingletonPattern.htm">Singleton 模式</a> 時擁有子類別的問題，在Singleton模式中的getInstance()通常是一個靜態方法，不能在子類別中重新定義它，關於子類別實例的產生交由getInstance()來進行是最好的選擇，例如：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Singleton {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Singleton instance = null;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private Singleton() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ....</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static Singleton getInstance() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (instance == null) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // getEnv表示系統環境變數</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String style = getEnv("style"); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (style.equals("child1"))</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = new ChildSingleton1();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (style.equals("child2r"))</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = new ChildSingleton2();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = new Singleton();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _instance;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; // ....</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
<br>上面這個程式片段改寫自 <a href="http://caterpillar.onlyfun.net/Gossip/DesignPattern/GoF.htm">Gof 書</a>中關於Singleton的例子，並用Java實現；在書中指出，這個例子的缺點是每增加一個子類別，getInstance()就必須重新修改，這個問題在Java中可以使用Reflection機制來解決：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Singleton {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Singleton instance = null;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private Singleton() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ....</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static Singleton getInstance() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (instance == null) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // getEnv表示環境變數</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String style = getEnv("style");</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = (Singleton)</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&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; Class.forName(style).newInstance();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Sorry! No such class defined!");</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instance;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; // ....</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
<br>上面的方式使用了Java的Reflection機制，並透過環境變數設定要產生的子類Singleton，如果不使用Reflection的話，Gof 書中提出的改進方法是使用Registry of Singleton方法：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">import java.util.*;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class Singleton {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; // 註冊表，用於註冊子類別物件</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Map registry = new HashMap(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; private static Singleton instance;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static void register(</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name, Singleton singleton) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; registry.put(name, singleton);</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public static Singleton getInstance() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (instance == null) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // getEnv表示取得環境變數</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String style = getEnv("style");</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = lookup(style);</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instance;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; protected static Singleton lookup(String name) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (Singleton) registry.get(name);</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
<br>在Gof書中使用List來實現註冊表，而在這邊使用HasMap類別來實現，它是由Java SE所提供的；在父類別中提供一個register() 以註冊Singleton的子類別所產生之實例，而註冊的時機可以放在子類別的建構方法中加以實現，例如： <br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">public class ChildSingleton1 extends Singleton {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; public ChildSingleton1() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ....</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 註冊子類別物件</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register(getClass().getName(), this);&nbsp; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp; }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">}</span><br></div>
&nbsp;<br>若要利用Singleton，則先使用這個子類別產生物件，這會向父類別註冊物件，之後透過Singleton父類別來取得物件：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">// 必須先啟始這段註冊程序</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">// 產生並註冊ChildSingleton1物件</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">new ChildSingleton1();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">// 產生並註冊ChildSingleton2物件</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">new ChildSingleton2();</span><br></div>
<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">// 註冊完成，可以使用父類別來取得子類的Singleton</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">// 至於取回何哪一個，視您的環境變數設置決定</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">Singleton childSingleton = Singleton.getInstance();</span><br></div>
&nbsp;<br><br>這種方式的缺點是您必須在程式中啟始一段程序，先向父類別註冊子類的Singleton，之後才能透過父類別來取得指定的子類別Singleton實例，好處是可以適用於沒有Reflection機制的語言，如果您想要改變Singleton父類傳回的子類Singleton，可以在上面的 Singleton類別中加入一個reset()方法，將instance設定為null，然後重新設定環境變數，之後再利用 Singleton父類的getInstance()方法重新取得註冊表中的其它子類。<br><br>事實上Registry of Singleton的真正優點正在於此，您可以使用父類別來統一管理多個繼承的子類別之Singleton實例，您可以在需要的時候再向父類別註冊子類 Singleton，必要時隨時調整傳回的子類別Singleton。<br>
<img src ="http://www.blogjava.net/jesson2005/aggbug/111167.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jesson2005/" target="_blank">张金鹏</a> 2007-04-17 10:33 <a href="http://www.blogjava.net/jesson2005/articles/111167.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Pattern: Factory Method 模式</title><link>http://www.blogjava.net/jesson2005/articles/111165.html</link><dc:creator>张金鹏</dc:creator><author>张金鹏</author><pubDate>Tue, 17 Apr 2007 02:32:00 GMT</pubDate><guid>http://www.blogjava.net/jesson2005/articles/111165.html</guid><wfw:comment>http://www.blogjava.net/jesson2005/comments/111165.html</wfw:comment><comments>http://www.blogjava.net/jesson2005/articles/111165.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jesson2005/comments/commentRss/111165.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jesson2005/services/trackbacks/111165.html</trackback:ping><description><![CDATA[考慮一個狀況，您所經營的工廠正在生產一個新的電視機產品，現在有一個問題發生了，您的電視機產品所有的組件都可以自行生產，像是操作面版、電源、搖控裝置等等等，但螢幕卻必須依賴另一個廠商或子廠商供應，這時您怎麼辦？<br><br>您不能將生產進度停下了，相反的您必須確定一些事情，您知道有關於螢幕控制的所有介面，您可以將這些對介面的操作溝通先實現，等到螢幕到了，直接將螢幕與您的半成品組合起來，一個完整的成品即可出廠。<br><br>Factory Method模式在一個抽象類中留下某個創建元件的抽象方法沒有實作，其它與元件操作相關聯的方法都先依賴於元件所定義的介面，而不是依賴於元件的實現，當您的成品中有一個或多個元件無法確定時，您先確定與這些元件的操作介面，然後用元件的抽象操作介面先完成其它的工作，元件的實作（實現）則推遲至實現元件介面的子類完成，一旦元件加入，即可完成您的成品。<br><br>再舉一個例子，假設您要完成一個文件編輯器，您希望這個編輯器可以適用於所有類型的檔案編輯，例如RTF、DOC、TXT等等，儘管這些文件有著不同的格式，您先確定的是這些文件必然具備的一些操作介面，例如儲存、開啟、關閉等等，您用一個IDocument類型來進行操作，這麼一來這個框架就無需考慮實際的儲存、開啟等細節是如何進行的。 <br><br>以 UML 類別圖來表現以下的概念： <br>
<div style="TEXT-ALIGN: center"><img title=FactoryMethod style="WIDTH: 565px; HEIGHT: 357px" alt=FactoryMethod src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/factoryMethod-1.jpg"><br></div>
<br>AbstractEditor中的createDocument()方法是個抽象方法，因為框架不知道您將實現一個什麼類型的文件，這個抽象方法將推遲至繼承AbstractEditor的子類中實現。<br><br>這個架構可用以下簡單的示意程式來作示範，當中實現了一個RTFDocument，雖然在AbstractEditor中並不知道我們會套用這個RTFDocument，但您可以看到，透過多型操作，您的框架可以進行對文件的相關操作。<br>
<ul>
    <li>AbstractEditor.java </li>
</ul>
<pre>public abstract class AbstractEditor {<br>    private IDocument document;<br>    public abstract IDocument createDocument();<br><br>    public void newDocument() { <br>        document = createDocument(); <br>        document.open();<br>    }<br><br>    public void saveDocument() { <br>        if(document != null) <br>            document.save(); <br>    }<br><br>    public void closeDocument() { <br>        if(document != null) <br>            document.close(); <br>    }<br>} <br></pre>
<br>
<ul>
    <li>IDocument.java </li>
</ul>
<pre>public interface IDocument {<br>    public void open();<br>    public void save();<br>    public void close();<br>} <br></pre>
<br>
<ul>
    <li>RTFEditor.java </li>
</ul>
<pre>public class RTFEditor extends AbstractEditor { <br>    public IDocument createDocument() { <br>        return new RTFDocument(); <br>    } <br>}                <br></pre>
<br>
<ul>
    <li>RTFDocument.java </li>
</ul>
<pre>public class RTFDocument implements IDocument {<br>    public RTFDocument() { <br>        System.out.println("建立RTF文件"); <br>    }<br><br>    public void open() { <br>        System.out.println("開啟文件"); <br>    }<br><br>    public void save() { <br>        System.out.println("儲存文件"); <br>    }<br><br>    public void close() { <br>        System.out.println("關閉文件"); <br>    }<br>}</pre>
<br>將Factory Method的結構繪出如下：<br>
<div style="TEXT-ALIGN: center"><img title=FactoryMethod style="WIDTH: 585px; HEIGHT: 357px" alt=FactoryMethod src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/factoryMethod-2.jpg"><br></div>
<br>Factory Method中的AbstractOperator中擁有一個抽象的factoryMethod()方法，它負責生成一個IProduct類型的物件，由於目前還不知道將如何實現這個類型，所以將之推遲至子類別中實現，在AbstractOperator中先實現IProduct操作介面溝通的部份，只要介面統一了，利用多型操作即可完成各種不同的IProduct類型之物件操作。<br><br>也就是說，對AbstractOperator來說，其操作的IProduct是可以抽換的。
<img src ="http://www.blogjava.net/jesson2005/aggbug/111165.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jesson2005/" target="_blank">张金鹏</a> 2007-04-17 10:32 <a href="http://www.blogjava.net/jesson2005/articles/111165.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Pattern: Abstract Factory 模式</title><link>http://www.blogjava.net/jesson2005/articles/111031.html</link><dc:creator>张金鹏</dc:creator><author>张金鹏</author><pubDate>Mon, 16 Apr 2007 09:41:00 GMT</pubDate><guid>http://www.blogjava.net/jesson2005/articles/111031.html</guid><wfw:comment>http://www.blogjava.net/jesson2005/comments/111031.html</wfw:comment><comments>http://www.blogjava.net/jesson2005/articles/111031.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jesson2005/comments/commentRss/111031.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jesson2005/services/trackbacks/111031.html</trackback:ping><description><![CDATA[假設您要製作一個對話方塊（Dialog）元件，您希望的是這個對話方塊可以有不同的視感（Look-and- feel），最基本的想法是，藉由Setter將不同視感的元件設定給這個對話方塊，例如：<br>
<ul>
    <li>CustomDialog.java </li>
</ul>
<pre>public class CustomDialog {<br>    private IButton button;<br>    private ITextField textField;<br>    <br>    public void setButton(IButton button) {<br>        this.button = button;    <br>    }<br>    <br>    public void setTextField(ITextField textField) {<br>        this.textField = textField;<br>    }<br><br>    public void layoutAllComponents() {<br>        // ....<br>    }<br>    <br>    public void showDialog() {<br>        this.paintDialog();<br>        button.paintButton();<br>        textField.paintTextField();<br>    }<br>  <br>    public void paintDialog() {<br>        System.out.println("custom dialog paints....");<br>    }<br>}</pre>
<br>很簡單，這是最基本的介面依賴，Setter依賴於IButton與ITextField兩個介面，而不是其實作類別，不過這邊還有個進一步的要求，使用上面的方式還必須親自呼叫Setter、layout等方法，您希望視感的更換可以更簡單些，例如只要透一個元件的替換就可以完成對話方塊上所有元件的視感更換。<br><br>您可以使用Abstract Factory模式，將所有對話方塊所需要的產生的元件加以封裝，對話方塊依賴於Abstract Factory，實際上具體的Factory實現則分別產生對話方塊所需要的視感元件，下面的 UML 類別圖展現這種概念。<br>
<div style="TEXT-ALIGN: center"><img title=AbstractFactory style="WIDTH: 673px; HEIGHT: 307px" alt=AbstractFactory src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/abstractFactory-1.jpg"></div>
<br>現在如果要更換所有的視感元件，就只要抽象掉具體的Factory就可以了，例如：<br>
<div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">CustomDialog windowsDialog = </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new CustomDialog(new WindowsWidgetFactory());</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">windowsDialog.showDialog();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">CustomDialog macDialog = </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new CustomDialog(new MacWidgetFactory());</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New,Courier,monospace">macDialog.showDialog();</span><br></div>
<br>來將上面的UML圖具體實現出來。<br>
<ul>
    <li>CustomDialog.java </li>
</ul>
<pre>public class CustomDialog {<br>    private IButton button;<br>    private ITextField textField;<br>    <br>    public CustomDialog(IWidgetFactory widgetFactory) {<br>        setWidgetFactory(widgetFactory);<br>    }<br>    <br>    // 由於客戶端只依賴於抽象的工廠，工廠如何實作並無關客戶端的事<br>    // 要抽換工廠並不需要改動客戶端的程式<br>    public void setWidgetFactory(IWidgetFactory widgetFactory) {<br>        setButton(widgetFactory.getButton());<br>        setTextField(widgetFactory.getTextField());<br>     <br>    }<br><br>    public void layoutAllComponents() {<br>        // layout all components<br>    }<br>    <br>    // 這邊也是依賴抽象，實際改變了元件實例<br>    // 客戶端代碼也不用更改<br>    public void setButton(IButton button) {<br>        this.button = button;    <br>    }<br>    <br>    public void setTextField(ITextField textField) {<br>        this.textField = textField;<br>    }<br>    <br>    public void showDialog() {<br>        this.paintDialog();<br>        button.paintButton();<br>        textField.paintTextField();<br>    }<br>  <br>    public void paintDialog() {<br>        System.out.println("custom dialog paints....");<br>    }<br>} <br></pre>
<br>
<ul>
    <li>IButton.java </li>
</ul>
<pre>public interface IButton {<br>    public void paintButton();<br>} <br></pre>
<br>
<ul>
    <li>ITextField.java </li>
</ul>
<pre>public interface ITextField {<br>    public void paintTextField();<br>} <br></pre>
<br>
<ul>
    <li>IWidgetFactory.java </li>
</ul>
<pre>public interface IWidgetFactory {<br>    public IButton getButton();<br>    public ITextField getTextField();<br>} <br></pre>
<br>
<ul>
    <li>MacButton.java </li>
</ul>
<pre>public class MacButton implements IButton {<br>    public void paintButton() {<br>        System.out.println("Mac button paints....");<br>    }<br>} <br></pre>
<br>
<ul>
    <li>WindowsButton.java </li>
</ul>
<pre>public class WindowsButton implements IButton {<br>    public void paintButton() {<br>        System.out.println("Windows button paints....");<br>    }<br>} <br></pre>
<br>
<ul>
    <li>MacTextField.java </li>
</ul>
<pre>public class MacTextField implements ITextField {<br>    public void paintTextField() {<br>        System.out.println("Mac textField paints....");<br>    }<br>} <br></pre>
<br>
<ul>
    <li>WindowsTextField.java </li>
</ul>
<pre>public class WindowsTextField implements ITextField {<br>    public void paintTextField() {<br>        System.out.println("Windows textField paints....");<br>    }<br>} <br></pre>
<br>
<ul>
    <li>MacWidgetFactory.java </li>
</ul>
<pre>public class MacWidgetFactory implements IWidgetFactory {<br>    public IButton getButton() {<br>        return new MacButton();<br>    }<br>    <br>    public ITextField getTextField() {<br>        return new MacTextField();<br>    }<br>} <br></pre>
<br>
<ul>
    <li>WindowsWidgetFactory.java </li>
</ul>
<pre>public class WindowsWidgetFactory <br>                          implements IWidgetFactory {<br>    public IButton getButton() {<br>        return new WindowsButton();<br>    }<br>    <br>    public ITextField getTextField() {<br>        return new WindowsTextField();<br>    }<br>}</pre>
<br>下圖是Abstract Factory模式的UML結構圖：<br>
<div style="TEXT-ALIGN: center">
<div style="TEXT-ALIGN: center"><img title=AbstractFactory style="WIDTH: 581px; HEIGHT: 266px" alt=AbstractFactory src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/abstractFactory-2.jpg"></div>
</div>
<br>簡單的說，在Abstract Factory模式中將具體的Product封裝在具體Factory實現中，而客戶仍只要面對Factory與Product的抽象介面，避免依賴於具體的Factory與Product，由於Factory封裝了所必須的Product，所以要更換掉所有的元件，只要簡單的抽換掉Factory就可以了，不用修改客戶端的程式。<br><br>
<img src ="http://www.blogjava.net/jesson2005/aggbug/111031.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jesson2005/" target="_blank">张金鹏</a> 2007-04-16 17:41 <a href="http://www.blogjava.net/jesson2005/articles/111031.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Pattern: Simple Factory 模式</title><link>http://www.blogjava.net/jesson2005/articles/111029.html</link><dc:creator>张金鹏</dc:creator><author>张金鹏</author><pubDate>Mon, 16 Apr 2007 09:39:00 GMT</pubDate><guid>http://www.blogjava.net/jesson2005/articles/111029.html</guid><wfw:comment>http://www.blogjava.net/jesson2005/comments/111029.html</wfw:comment><comments>http://www.blogjava.net/jesson2005/articles/111029.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jesson2005/comments/commentRss/111029.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jesson2005/services/trackbacks/111029.html</trackback:ping><description><![CDATA[Simple Factory模式（又稱Static Factory模式），一個Simple Factory生產成品，而對客戶端隱藏產品產生的細節。實作時定義一個產品介面（interface），並透過特定靜態方法來建立成品。<br><br>假設有一個音樂盒工廠，購買音樂盒的客人不用知道音樂盒是如何製作的，他只要知道如何播放音樂盒就可以了，以 UML 類別圖來表示以上的概念：<br>
<div style="TEXT-ALIGN: center"><img title=SimpleFactory style="WIDTH: 608px; HEIGHT: 228px" alt=SimpleFactory src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/simpleFactory-1.jpg"><br></div>
如上圖所示的，MusicBoxDemo代表了客戶的角色，它只依賴於IMusicBox介面，而不關心特定的實作，實際如何產生IMusicBox的實例由MusicBoxFactory完成，以一個簡單的程式來實現上面這個UML類別圖：<br>
<ul>
    <li>IMusicBox.java </li>
</ul>
<pre>public interface IMusicBox {<br>    public void play();<br>}</pre>
<br>
<ul>
    <li>PianoBox.java </li>
</ul>
<pre>public class PianoBox implements IMusicBox {<br>    public void play() {<br>        System.out.println("撥放鋼琴音樂:)");<br>    }<br>}</pre>
<br>
<ul>
    <li>ViolinBox.java </li>
</ul>
<pre>public class ViolinBox implements IMusicBox {<br>    public void play() {<br>        System.out.println("撥放小提琴音樂^_^");<br>    }<br>}</pre>
<br>
<ul>
    <li>MusicBoxFactory.java </li>
</ul>
<pre>public class MusicBoxFactory {<br>    public static IMusicBox createMusicBox(String name) <br>                               throws InstantiationException, <br>                                      IllegalAccessException, <br>                                      ClassNotFoundException {<br>        // 這邊使用的是Java的Reflection機制來產生實例<br>        // 不過客戶端不用管啦<br>        // 以後就算改變了這邊的程式，客戶端程式是不用更改的<br>        return (IMusicBox) Class.forName(name).newInstance();<br>    }<br>}</pre>
<br>
<ul>
    <li>MusicBoxDemo.java </li>
</ul>
<pre>public class MusicBoxDemo {<br>    public static void main(String[] args) throws Exception {<br>        playMusicBox(MusicBoxFactory.createMusicBox("PianoBox"));<br>        playMusicBox(MusicBoxFactory.createMusicBox("ViolinBox"));<br>    }<br>    <br>    public static void playMusicBox(IMusicBox musicBox) {<br>        musicBox.play();<br>    }<br>}</pre>
<br>由於客戶端只依賴於IMusicBox介面，所以即使您日後改變了createMusicBox()中的實作方式，對客戶端是一點影響也沒有的。<br><br>來看看Simple Factory的類別結構：<br>
<div style="TEXT-ALIGN: center"><img title=SimpleFactory style="WIDTH: 595px; HEIGHT: 215px" alt=SimpleFactory src="http://caterpillar.onlyfun.net/Gossip/DesignPattern/images/simpleFactory-2.jpg"></div>
<br>客戶只要面對Factory，客戶依賴於產品介面，產品的具體實作是可以與客戶隔開的，它們也是可以抽換的。<br><br>
<img src ="http://www.blogjava.net/jesson2005/aggbug/111029.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jesson2005/" target="_blank">张金鹏</a> 2007-04-16 17:39 <a href="http://www.blogjava.net/jesson2005/articles/111029.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>