書中先提到使用 singleton 的缺點: 會難以測試程式。畢竟, 使用 singleton 的必要條件是設定 constructor 的存取級別為 private。若要減輕這個問題, 可幫 singleton 加上 interface, 而不是直接用 singleton 的 class 來使用它的 methods。不過我想沒什麼人會想這麼做, 要寫兩套 signature, 挺麻煩的。
查了一下相關資訊, EasyMock 有提到它無法 mock private 或 final method (見 官網文件的 "Class Mocking Limitations" ), 看來 EasyMock 是用繼承的方式 mock class, 所以有此限制吧。vgod 提到 PowerMock 可 mock private, final, static methods, 官網提到它的作法是換掉 class loader, 有機會再來試試。至少知道還是有辦法測試 singleton, 只是可用手段較少, 或許也有一些其它副作用吧。
關於 singleton 更多的弊端, 可參見 Miško Hevery 的文章:
- Flaw: Brittle Global State & Singletons
- ote the code that way. But to anyone new on the project, this is a total myste
- Where Have All the Singletons Gone?
在 java 5.0 開始, 用 enum 實作 singleton 又好寫又好用, 只要這麼寫即可:
public enum MyClass { INSTANCE; public void someOperation() { .. } }enum 的語法可直接做出「singleton」, Making the Most of Java 5.0: Enum Tricks 提供滿不錯的例子介紹使用 enum 的技巧, 像是各別定義各個物件的方法。
至於 java 5.0 前, 實作 singleton 有兩種選擇, 兩者都需要 private constructor, 差別在於取得 singleton 的方式:
- 用 public static final MyClass INSTANCE = new MyClass()
- 類似前者, 但改設 INSTANCE 的存取級別為 private, 改用 public static MyClass getInstance() 取得物件
用 class 實作 singleton 時要另外注意 serialization, 記得寫 readResolve() 避免在 deserialization 時產生第二個 object。所以整體來看, 作者認為使用 enum 並只放一個元素 (INSTANCE) 是比較明智的選擇。
但是, 使用 enum 也會更難 mock。EasyMock 不行, 而 PowerMock 似乎可以。還有, 通常用 enum 時會看作 constant 外加一些輔助函式, 不會有太複雜的 state。但若用 enum 實作 singleton, 很可能會有複雜的初始化, 或需要存取外部資源。這樣測試時就必須 mock enum 了。
沒有留言:
張貼留言