Java 私有構造函數的應用

 在Java中,構造函數的訪問級別通常是public, 它提供了一個構造該類對象的接口。可是你知不知道,把構造函數的級別設爲private, 有一些特別用處。

先來看一段代碼:
//Shape.java
public class Shape {
    private Shape() {
       /* set something here */
    }

    public static Shape makeShape(/* arglist */) {
       System.out.println("here is the shape you ordered");
       return (new Shape());
    }

    public static void main(String args[]) {
         Shape.makeShape();
    }
}
首先從語言角度分析,我們可以知道, 任何類的使用者都無法使用構造函數來生成一個圖形, 因爲構造函數是私有的,無法被類以外的函數使用。而只能通過調用makeShape來實現。

也許你會問,爲什麼不直接使用構造函數來生成圖形,而需要使用一個看上去多餘的makeShape方法呢?

這樣做有以下幾個好處:

1。你可以返回任何的Shape類型,包括Shape的子類。比如你可以把makeShape寫成這樣:

       public static Shape makeShape(/* arglist */) {
       System.out.println("here is the shape you ordered");
       if (retangle)
             return (new Retangle(/* arglist*/));
       if (Circle)
            return (new Circle(/* arglist */));
    /* you can return as many shapes as you like */
    }

    這裏假設Retangle 和 Circle 都是shape的子類,並且和Shape類在同一個包內,Shape類可以訪問子類的構造函數。這樣shape就提供了一個圖形工廠。 用戶通過一個接口就可以生成不同的圖形。事實上,這種用法被稱爲“工廠模式”。

2。可以實現一個類只有一個對象。請看下面的代碼

       //Handler.java
public class Handler {
   
    private Handler handler = null;
    private Handler() {
       /* set something here */
    }

    public static getHandler(/* arglist */) {
        if (!handler)
             handler = new Handler();
       return handler;
    }

    public static void main(String args[]) {
         Handler.getHandler();
    }
}

當handlerw爲空時,那麼重新構造一個handler,然後返回;如果已經構造過了,那麼就直接返回已經存在的handler。這種用法被稱爲“Singleton pattern". 如果直接使用構造函數來構造對象,那麼你就無法控制生成的數量。在實際應用中,往往會做一些改變。比如使用一個具有一定容量的池,當需要構造一個對象而池的容量仍未滿時,就構造一個新的對象,並放入池中,並把對象的狀態設爲“佔用”狀態;當需要構造一個對象而池的容量已滿,則從池中選一個“空閒”狀態的對象返回,並把對象的狀態設爲“佔用”。當對象使用完後再回收到池中並把狀態設爲“空閒“。

 這種模式的一個典型應用場景是:

    在一個具有很多用戶的web站點裏,需要一個對象來單獨處理一個連接,而每一個連接的時間比較短。如果每次連接都創建一個對象然後又很快銷燬,那麼創建和銷燬對象的系統開銷是很大的。這種時候可以使用對象池,這樣就免去了創建和銷燬對象的開銷。

3。可以方便的拋出異常。請看下列代碼:

       public class Test {
        public Test() {
                double x = 1.0/0.0;
        }
        public static void main(String args[]) {
        try {
                Test test = new Test();
        }catch (Exception e){
                System.out.println(e.toString());
        }
  }
}

編譯,執行,你會發現這個異常不會被捕捉,沒有任何輸出;即使嘗試在構造函數中捕捉異常也不行。看下列代碼:

public class Test {
        public Test() {
                try {
                System.out.println("trying to throw an exception");
                double x = 1.0/0.0;
                } catch(Exception e) {
                        System.out.println("Exception captured");
                }finally {
                        System.out.println("inside finally");
                }
        }
        public static void main(String args[]) {
                Test test = new Test();
        }
}
編譯,運行,結果爲:
trying to throw an exception
inside finally

原因是JVM把構造函數產生的異常丟棄了。試想你正在使用一個第三方的類庫提供的類,那個類提供一個共有的構造函數,它允許你通過參數構造一個類的對象,可是如果你的參數不合法,導致在構造函數中產生一個異常,那麼你永遠不知道具體發生了什麼。當然如可以在每次構造對象時進行參數合法性檢查,可是假設你要構造好多這樣的對象??那將是一場災難。這時可以通過把構造函數的訪問級別設爲私有,強迫類的使用者使用一個工廠函數來生成需要的對象,那麼就可以在這個函數中統一的進行參數檢查了。具體的代碼就不寫了,留給讀者去實踐吧!

從上面的分析我們可以知道私有構造函數的威力。需要注意的一點是,即使你的構造函數什麼都不做,比如:
private Shape() {}
你仍然要顯示的定義,因爲如果你不定義,那麼Java會自動爲你生成一個空構造函數,而這個空構造函數是共有的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章