l

2014年4月17日 星期四

重新整理Singleton Pattern,Take 2

Mar.19 11:30~12:00

螢幕截圖 2014-03-19 11.55.29

 

話說這幾天又重新開始著手整理pattern,昨天介紹了重新整理第二次的Factory Method,今天看一下Singleton。先看一下第一版的內容:

Name:Singleton(take 1)

Context:主流的物件導向程式語言允許我們自由地從一個類別產生多個實例,但卻沒有直接支援可以控制一個類別產生實例個數的機制。

Problem:如何產生一個物件?

Force:

  • 你設計的類別代表了在真實世界中的特定情境之下,只會存在一份實例且具有狀態的「實體」、「服務」或「概念」,例如硬體的輸入/輸出埠、GPS、時鐘、印表機多工緩衝處理程式、檔案系統;而非在某種情境下,某個類別恰巧只需要產生一個實例。
  • 這個單一實例要很容易地被其他物件存取。

Solution:在類別中宣告一個型別為類別本身的靜態成員變數(static data member)作為回傳客戶端的單一實例。把類別的建構元改成非公開以防客戶端直接產生此類別的實例。最後在類別中定義一個靜態的getInstance()方法,傳回這個單一實例靜態成員變數。

***

以下是整理過後的第二版,同樣是把若干force移到context裡面。原本從「程式語言產生物件的方式」這個角度來作為context,感覺有點太特定、過於窄化。

Name:Singleton(take 2)

Context: 你設計一個類別用來代表在真實世界中具有狀態且只存在一份的「實體」、「服務」、或「概念」,例如硬體裝置的輸入/輸出埠、手機上的GPS、主機板上的時鐘、印表機多工緩衝處理程式、檔案系統等;而非在某種情境下,某個類別恰巧只需要產生一個實例。

Problem: 如何產生一個物件?

Force:

  • 幫這個類別產生多個不同實例不僅浪費記憶體,還很可能導致程式錯誤。
  • 系統中的其他物件如果無法很方便的存取這個類別的實例,就失去產生該實例的意義。

Solution: 在類別中宣告一個型別為類別本身的靜態成員變數(static data member)作為回傳客戶端的單一實例。把類別的建構函數成非公開以防客戶端直接產生此類別的實例。最後在類別中定義一個靜態的getInstance函數,傳回這個單一實例靜態成員變數。

***

比較一下take 1和take 2的寫法,鄉民們覺得哪一種敘述比較清楚,歡迎提供一些回饋意見。最後,再看一個生活版的Singleton。

Name:Singleton(生活版)

Context: 公司裡面有一台可以接上網路的印表機,所有的員工都可以使用這台印表機來列印資料。

Problem: 如何使用這台印表機?

Force:

  • 雖然每位員工的電腦上都安裝了這台印表機的驅動程式,但是實體印表機還是只有一台,並不會因為因此變成N台印表機。大家一起列印文件的時候還是需要依據先來後到,或是列印優先順序來排隊,否則列印出來的文件內容可能會穿插不同人的資料。
  • 員工安裝印表機驅動程式時,只要知道印表機的名稱或是IP位址就可以使用它。

Solution: 幫實體印表機設計一個「印表機類別」,「印表機類別」中宣告一個型別為自己的靜態成員變數(static data member)作為回傳給員工(客戶端)電腦上印表機驅動程式所代表的印表機。把「印表機類別」的建構函數改成私有(private)以防員工直接產生印表機實例。最後在印表機類別中定義一個靜態getInstance函數,傳回這個單一實例靜態成員變數。

***

友藏內心獨白:生活版的solution好像不是很「生活」啊挑眉質疑

1 則留言:

  1. 雖吾未有閒時對design pattern 作深入研究,然於吾之見, take 1 take 2出現之原因皆出於汝對於context, force 之定義有了不同想法,如 context 新義應否為 實作之困境之特點 及 現有方法之不足. 故吾以為汝煩惱根源在於汝已隱有新之定義之想,而吾愚見為同時審視眾take 1 take 2 異同之處,理出新定義即可.

    回覆刪除