iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
Software Development

深入淺出Java 30天系列 第 2

Day 2: 盡量使用static factory method,而不是constructor

  • 分享至 

  • xImage
  •  

雖然使用constructor直覺又快速,但是使用static factory method去create instance,還是比constructor好,當然也會有一些缺點,下面將分析這些優缺點:

優點1

因為constructor沒有名稱,會讓使用者難以知道要如何使用,透過static method去create或取得物件,會更清楚知道使用這個method做這件事的目的,可以依照不同需求,設計不同的static method,而不是像constructor,只能設計不同參數數量的多個constructor,使用者要使用時,還要弄懂每個constructor符不符合自己的需求。

優點2

使用static factory method可以避免產生重複的object,如果使用constructor取得物件的話,每次都會create一個新的物件,但是如果是使用使用static method取得物件,如果相同的物件已經create過了,並且被cache住,就可以直接取用現有的物件,不需要再重複產生,這樣可以讓效能更佳,在記憶體比較珍貴的地方,這個優點會特別重要。

優點3

如果需要根據不同的參數,回傳不同類型的subclass,使用static method也可以根據不同情境取得所需的subclass,舉例來說,要知道動物中大象腳的數量,可以在Animals這個class透過method取得Elephant這個實作Animal的instance,如果是直接用Animals的constructor,無法直接Animals透過取得Elephant的instance,還是需要透過Elephant的類別實體化,會少了一點彈性。

interface Animal {
    public int getFootNumber();
}

class Elephant implements Animal {
    public int getFootNumber() {
        return 4;
    }
}

class Monkey implements Animal {
    public int getFootNumber() {
        return 2;
    }
}

public class Animals {
    private Animals() {};
    public static Animal newInstance(String name) {
        if (name.equals("elephant")) {
            return new Elephant();
        } else if (name.equals("monkey")) {
            return new Monkey();
        }
        return null;
    }
    
    public static void main(String[] args) {
        Animal elephant = Animals.newInstance("elephant");
        System.out.println("foot number: " + elephant.getFootNumber());
    }
}

優點4

可以不用一開始就決定type parameter的型別。以hashmap為例,在一開始宣告的時候,如果是透過constructor,Java 7之前必須在new instance的時候指定type parameter的型別,因此會需要寫重複的程式碼,變得很冗長。

Map<String, List<String>> m = new HashMap<String, List<String>>();

但透過static factory method的方式,可以先把類別的type parameter宣告成泛型,然後在宣告的時候,在透過宣告的參數型別指定type parameter的型別,程式碼會變得比較簡潔。

public class HashMap{
    public static <K, V> HashMap<K, V> newInstance() {
        return new HashMap<K, V>();
    }
}

Map<String, List<String>> m = HashMap.newInstance();

但在Java 7之後引入了Diamond Operator之後,讓編譯器可以自行推斷物件實體化之後的type parameter的型別,更近一步的簡化寫法,這個優點就沒有那麼明顯。

Map<String, List<String>> m = new HashMap<>();

缺點1

如果將constructor設為private,那麼class會無法被繼承,在編譯的時候會出現錯誤。

class Animals {
    private Animals() {};
    public static Animal newInstance(String name) {
        if (name.equals("elephant")) {
            return new Elephant();
        } else if (name.equals("monkey")) {
            return new Monkey();
        }
        return null;
    }
}

class Life extends Animals {
}

缺點2

因為不像constructor有特殊意義,大家知道可以拿來new instance,自行寫static factory method取代constructor的功能,容易跟其他static method的功能混淆。


上一篇
Day 1: Effective java簡介
下一篇
Day 3: 當constructor需要很多參數時,考慮使用builder(上)
系列文
深入淺出Java 30天12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
Penut Chen
iT邦新手 1 級 ‧ 2024-08-02 13:41:54

factor or factory?

hjoru iT邦新手 5 級 ‧ 2024-08-02 13:44:01 檢舉

感謝提醒,是factory!

我要留言

立即登入留言