或許最簡單的設計范式就是“單子”(Singleton),它能提供對象的一個(而且只有一個)實例。單子在Java庫中得到了應用,但下面這個例子顯得更直接一些:
//: SingletonPattern.java // The Singleton design pattern: you can // never instantiate more than one. package c16; // Since this isn't inherited from a Cloneable // base class and cloneability isn't added, // making it final prevents cloneability from // being added in any derived classes: final class Singleton { private static Singleton s = new Singleton(47); private int i; private Singleton(int x) { i = x; } public static Singleton getHandle() { return s; } public int getValue() { return i; } public void setValue(int x) { i = x; } } public class SingletonPattern { public static void main(String[] args) { Singleton s = Singleton.getHandle(); System.out.println(s.getValue()); Singleton s2 = Singleton.getHandle(); s2.setValue(9); System.out.println(s.getValue()); try { // Can't do this: compile-time error. // Singleton s3 = (Singleton)s2.clone(); } catch(Exception e) {} } } ///:~
創建單子的關鍵就是防止客戶程序員采用除由我們提供的之外的任何一種方式來創建一個對象。必須將所有構建器都設為private(私有),而且至少要創建一個構建器,以防止編譯器幫我們自動同步一個默認構建器(它會自做聰明地創建成為“友好的”——friendly,而非private)。
此時應決定如何創建自己的對象。在這兒,我們選擇了靜態創建的方式。但亦可選擇等候客戶程序員發出一個創建請求,然後根據他們的要求動態創建。不管在哪種情況下,對象都應該保存為“私有”屬性。我們通過公用方法提供訪問途徑。在這裡,getHandle()會產生指向Singleton的一個句柄。剩下的接口(getValue()和setValue())屬於普通的類接口。
Java也允許通過克隆(Clone)方式來創建一個對象。在這個例子中,將類設為final可禁止克隆的發生。由於Singleton是從Object直接繼承的,所以clone()方法會保持protected(受保護)屬性,不能夠使用它(強行使用會造成編譯期錯誤)。然而,假如我們是從一個類結構中繼承,那個結構已經過載了clone()方法,使其具有public屬性,並實現了Cloneable,那麼為了禁止克隆,需要過載clone(),並擲出一個CloneNotSupportedException(不支持克隆違例),就象第12章介紹的那樣。亦可過載clone(),並簡單地返回this。那樣做會造成一定的混淆,因為客戶程序員可能錯誤地認為對象尚未克隆,仍然操縱的是原來的那個。
注意我們並不限於只能創建一個對象。亦可利用該技術創建一個有限的對象池。但在那種情況下,可能需要解決池內對象的共享問題。如果不幸真的遇到這個問題,可以自己設計一套方案,實現共享對象的登記與撤消登記。