2011-08-30 141 views
2

我奮力選擇此方案的完美設計模式:新的類實例VS Singleton類VS靜態方法

當我點擊我的揮杆UI的瀏覽按鈕,指定的URL必須在打開網頁瀏覽器。此功能是這個工具類,它看起來像這裏面的實現:

//inside action Listener of the browse button I call the openURL method of the below class 

class webBrowserUtility(){ 
    void openURL(String url){ 
    ........ 
    } 
} 

設計模式的方法

方法1)我可以繼續創建上述類的新實例,並調用的OpenURL()。方法2)Singleton:使WebbrowserUtility類成爲單例,並在內存中保留該類的靜態實例,以便在需要時調用該方法。方法3)靜態方法:使openURL()方法靜態並根據需要調用WebbrowserUtility.openURL(url)。

在我的第一種方法中,我擔心它可能效率低下,因爲每次點擊瀏覽按鈕都會創建一個WebBrowserUtility類的新實例。我對選擇2)和3)之間的適應方法感到困惑。你能幫我選擇這三種設計模式中最好的一種嗎?還是有更好的設計模式可以適應相同的?

+0

那麼,['Desktop.browse()'](http://download.oracle.com/javase/7/docs/api/java/awt/Desktop.html#browse(java.net.URI))已選擇方法2. –

回答

2

首先,我建議你不要過於擔心的可能性除非你有一些具體的理由相信這將是一個問題,否則在這個階段的表現/效率問題。等一下,看看它是否真的有問題,然後相應地解決它。但是你可能會發現沒有什麼可擔心的。

所以,問題是,你的WebBrowserUtility是否使用類的任何非靜態成員變量(即實例數據)?

  • 如果確實如此,那麼您必須按照方法1進行操作,並且每次都創建一個新實例。

  • 如果沒有,那麼我會傾向於使用靜態方法,並使WebBrowserUtility爲靜態類而不是實現單例。你不需要真的需要只有一個實例,這是單身模式的用途。靜態類解決方案的靜態方法爲您提供了所需的易用性。不足之處在於,如果你正在爲此編寫單元測試,那麼對靜態方法進行適當的單元測試是有問題的。

+1

+1用於考慮測試。 – jstephenson

2

在這種情況下,我個人會使用靜態方法,因爲您的openURL方法不使用任何類屬性,所以不需要類實例來支持它。

0

您是否需要在WebBrowserUtility類中保留狀態(例如成員變量,計數器等)?

如果是:您是否需要此狀態爲全局可用或同步?方法2 ...另有1)

如果沒有:那麼這是一個簡單的靜態實用工具類,去一個靜態方法的靜態類

2

個人而言,我會選擇的方法3,如只要這個例子的範圍擴大,有沒有出現任何需要存儲的對象狀態,並有從單擊處理直接使用。

當然,這裏的侷限性是,你不能像在單例中那樣繞過類的一個實例,但即使這是必要的,也不可能因爲它缺少狀態而實際上會存在要求通過一個單獨限制實例的數量,所以你可能不應該使用反正單身。

我希望這會有所幫助。

+0

從我+1,因爲[你和我本質上是說同樣的事情](http://stackoverflow.com/questions/7242297/new-class-instance-vs-singleton-class-vs-static-method/7242406 #7242406)。 – razlebe

1

單身人士濫用爲限制實例數量的方式,因爲這是沒有必要經常像一些人認爲。我認爲它們比靜態方法更容易作爲一種測試方法。使用靜態方法意味着您不能輕鬆地將您的真實Web瀏覽器實用程序類用於模擬或測試加倍。這是否是一個問題是由你來決定的。

我在這裏可能仍然會使用靜態方法,如果需要修改WebBrowserUtility類以在內部使用單例實例,並允許客戶端代碼根據需要將此實例設置爲測試版本。請參見Working Effectively with Legacy Code中的「介紹靜態設置器」。

4

有沒有最終正確回答你的問題。不需要尋找那個。其實什麼而對於一些的軟件設計架構應該明白的是:當你不知道做正確的事情 - 只是用一種抽象。那麼如果你最終會理解你最初的實現是不正確的,那麼你只需將它替換爲另一個,而不必改變公共接口。

我的意思是在你的情況並不明顯:從一個側面,你應該用一個單一實例去那麼無需實例很多情況下,佔用更多的內存和對象的創建引入額外的開銷。然而從另一個側面,你不能確定你的項目的要求不會改變 - 也許你會有一些狀態添加到您的WebBrowserUtility服務,使許多並行調用保持的狀態不一樣不同消費者的,或者可能甚至想爲您的課程實施實例池。你無法預測未來,這就是爲什麼你應該使用抽象。

抽象的對象實例化的最簡單方法是使用靜態工廠方法並調用它像getInstance() - 就像如果你要實現一個單身,但不只是在條款想想單例實現 - 這僅僅是如何實例化它的抽象。現在你可以堅持使用單例,所以這種方法將永遠返回服務的唯一實例,但是在將來,如果你需要改變類的創建方式,你將只需更改getInstance()實現,而無需更改任何代碼實際上使用您的服務。所以你不必現在決定哪種方式更好,直到你有足夠的信息來選擇。

因此,使用factory methods實例化您的服務可爲您提供更大的靈活性,但還有更好的方法。如果你繼續發展關於實例化抽象的想法,你會明白通常你想將創建代碼從實際服務中移出到專用的factory class中,因爲有時候你想用不同的方式以不同的方式實例化相同的服務。這個想法的進一步發展最終會使用控制反轉模式,這是如何創建服務實例並管理它們之間的依賴關係的最終答案。

如果您使用的是Java,看看非常流行的Spring framework,允許您定義配置文件服務創建的規則,所以如果你需要一個原型而不是單例,這只是改變這種的問題配置文件。

我也不鼓勵將你的服務類實現爲一些具有所需邏輯的靜態方法。這背後的原因 - 它現在可以簡單快速地實現,但將來你手中的東西將與定義靜態方法的接口捆綁在一起。因此,如果最終需要使用多個實例,則必須更改使用靜態方法的使用者代碼,因爲靜態簽名位於您的界面中,而不僅僅是在您的實現中。相比之下,在實例化代碼中隱藏原型/單例之間的區別,因此消費者不關心實例是如何創建的 - 他們只是要求實例並獲取它。