程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 考慮使用靜態工廠方法替代構造方法,靜態構造

考慮使用靜態工廠方法替代構造方法,靜態構造

編輯:JAVA綜合教程

考慮使用靜態工廠方法替代構造方法,靜態構造


創建對象

構造方法創建對象

在Java中,創建對象常用的方法是通過公有構造方法創建;

舉個例子:如下,是Boolean類的一個構造方法,以及通過該構造方法創建一個Boolean對象;

    public Boolean(String s) {
        this(toBoolean(s));
    }
Boolean bTrue = new Boolean("true");

靜態工廠方法創建對象

其實,創建對象還有另外一種方法,通過公有靜態工廠方法來創建對象,不過這種方法往往容易被程序員忽略;

舉個例子,如下是Boolean類的valueOf方法,以及通過該靜態工廠方法返回的Boolean實例,注意,這裡並沒有創建Boolean實例對象,而是返回事先創建好的Boolean對象;

    public static Boolean valueOf(String s) {
        return toBoolean(s) ? TRUE : FALSE;
    }
Boolean bTrue = Boolean.valueOf("true");

注意區分靜態工廠方法和工廠方法模式

注意,這裡的靜態工廠方法與設計模式裡的工廠方法模式不是一個概念:

  • 靜態工廠方法通常指的是某個類裡的靜態方法,通過調用該靜態方法可以得到屬於該類的一個實例;
  • 工廠方法模式是一種設計模式,指的是讓具體的工廠對象負責生產具體的產品對象,這裡涉及多種工廠(類),多種對象(類),如內存工廠生產內存對象,CPU工廠生產CPU對象;

不過,如果要說相似的話,靜態工廠方法跟簡單工廠模式倒有那麼點像,不過區別也挺大,簡單工廠模式裡的靜態工廠方法會創建各種不同的對象(不同類的實例),而靜態工廠方法一般只創建屬於該類的一個實例(包括子類);

使用靜態工廠方法的優勢

1、可讀性更強

 假設我們需要寫一個產生隨即數的類RandomIntGenerator,該類有兩個成員屬性:最小值min和最大值max,

假設我們的需求是需要創建三種類型的RandomIntGenerator對象,

1、大於min,小於max;

2、大於min 小於Integer.MAX_VALUE;

3、大於Integer.MIN_VALUE 小於max

如果我們不使用靜態工廠方法,代碼一般如下設計:

class RandomIntGenerator
{
    /**
     * 最小值
     */
    private int min = Integer.MIN_VALUE;
    /**
     * 最大值
     */
    private int max = Integer.MAX_VALUE;

    /**
     * 大於min 小於max
     * @param min
     * @param max
     */
    public RandomIntGenerator(int min, int max)
    {
        this.min = min;
        this.max = max;
    }
    
    /**
     * 大於min 小於Integer.MAX_VALUE
     */
    public RandomIntGenerator(int min)
    {
        this.min = min;
    }

//    報錯:Duplicate method RandomIntGenerator(int) in type RandomIntGenerator
//    /**
//     * 大於Integer.MIN_VALUE 小於max
//     */
//    public RandomIntGenerator(int max)
//    {
//        this.max = max;
//    }
}

觀察以上代碼,我們發現,以上代碼不僅可讀性差(new RandomIntGenerator(1, 10)與new RandomIntGenerator(10),不查文檔,不看注釋很難知道其創建的對象的具體含義),而且在設計最後一個構造方法的時候,還報錯,因為已經存在一個參數一致的工作方法了,提示重復定義;

那麼假設我們使用靜態工廠方法會怎樣呢,如下所示:

class RandomIntGenerator
{
    /**
     * 最小值
     */
    private int min = Integer.MIN_VALUE;
    /**
     * 最大值
     */
    private int max = Integer.MAX_VALUE;

    /**
     * 大於min 小於max
     * @param min
     * @param max
     */
    public RandomIntGenerator(int min, int max)
    {
        this.min = min;
        this.max = max;
    }
    /**
     * 大於min 小於max
     * @param min
     * @param max
     */
    public static RandomIntGenerator between(int min, int max)
    {
        return new RandomIntGenerator(min, max);
    }
    /**
     * 大於min 小於Integer.MAX_VALUE
     */
    public static RandomIntGenerator biggerThan(int min)
    {
        return new RandomIntGenerator(min, Integer.MAX_VALUE);
    }

    /**
     * 大於Integer.MIN_VALUE 小於max
     */
    public static RandomIntGenerator smallerThan(int max)
    {
        return new RandomIntGenerator(Integer.MIN_VALUE, max);
    }
}

成功滿足需求:創建三種類型的RandomIntGenerator對象,而且創建對象的時候,代碼可讀性比使用構造方法強;

2、調用的時候,不需要每次都創建一個新對象

JDK中的Boolean類的valueOf方法可以很好的印證這個優勢,在Boolean類中,有兩個事先創建好的Boolean對象(True,False)

public final class Boolean implements java.io.Serializable,
                                      Comparable<Boolean>
{
    /**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code true}.
     */
    public static final Boolean TRUE = new Boolean(true);

    /**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code false}.
     */
    public static final Boolean FALSE = new Boolean(false);

當我們調用Boolean.valueOf("true")方法時,返回的就是這兩個實例的引用,這樣可以避免創建不必要的對象,如果使用構造器的話,就達不到這種效果了;

    public static Boolean valueOf(String s) {
        return toBoolean(s) ? TRUE : FALSE;
    }

 3、可以返回原返回類型的任何子類型對象

    //RedDog和BlackDog為Dog的子類
    public static Dog getInstance(){
        return new RedDog();//或者return new BlackDog();
    }

4、代碼更加簡潔

package tmp;


class MyMap<K,V> {
    /**
     *
     */
    public MyMap()
    {

    }

    public static <K,V> MyMap<K,V> newInstance(){
        return new MyMap<K, V>();

    }
}

public class Main
{
    public static void main(String[] args)
    {
        MyMap<String, String> map1 = new MyMap<String, String>();

        //更加簡潔,不需要重復指明類型參數,可以自行推導出來
        MyMap<String, String> map2 = MyMap.newInstance();
    }


}

使用靜態工廠方法的缺點

 1、如果類不含public或protect的構造方法,將不能被繼承;

如下類,不能被其它類繼承;

class MyMap<K,V> {
    /**
     *
     */
    private MyMap()
    {

    }

    public static <K,V> MyMap<K,V> newInstance(){
        return new MyMap<K, V>();

    }
}

2、與其它普通靜態方法沒有區別,沒有明確的標識一個靜態方法用於實例化類

 所以,一般一個靜態工廠方法需要有詳細的注釋,遵守標准的命名,如使用getInstance、valueOf、newInstance等方法名;

 

 參考自effective java第一條

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved