2009-11-04 34 views
11

我一直在閱讀,通過在代碼中使用靜態類/單例,創建依賴項,是不好的形式,併產生問題,即。緊耦合和單元測試。實用程序類別..好還是壞?

我有一個情況我有一組是沒有與之相關聯的狀態,並執行僅使用方法的輸入參數的操作URL解析方法。我相信你對這種方法很熟悉。

在過去,我會着手創建一個類,並添加這些方法,直接從我的代碼如給他們打電話。

UrlParser.ParseUrl(url); 

但是等一下,那就是引入了對另一個類的依賴。我不確定這些'效用'類是否是壞的,因爲它們是無狀態的,並且這最大限度地減少了所述靜態類和單例的一些問題。有人能澄清這一點嗎?

我應該移動的方法來調用類,即如果只是調用的類將使用的方法。這可能違反「單一責任原則」。

+0

「我有一種情況,我有一組url解析方法,它們沒有與它們相關聯的狀態,並且只使用方法的輸入參數執行操作,我相信你很熟悉這種方法。這種方法將被稱爲純函數 – morphles 2011-05-02 09:51:37

+0

檢查此博客文章(主要談論Java,但仍然在這裏相關):http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes。 html – yegor256 2014-05-06 11:13:14

回答

7

從理論設計的角度來看,我覺得應用類是可以避免的。它們基本上和靜態類沒有什麼不同(雖然稍微好一些,因爲它們沒有狀態)。

然而,從實際的角度來看,我確實創造了這些,並鼓勵他們在適當的時候使用。試圖避免使用實用程序類通常很麻煩,並且導致代碼不易維護。但是,我儘可能鼓勵我的開發人員在公共API中避免使用這些API。

例如,你的情況,我覺得UrlParser.ParseUrl(...)可能更好地處理爲一個類。查看BCL中的System.Uri - 這爲處理統一資源標識符處理乾淨,易於使用的界面,運行良好,並保持實際狀態。我更喜歡這種方法來處理字符串的實用方法,並強制用戶繞過字符串,記住驗證它,等等。

+0

好點。 System.Uri是將這種靜態工具方法轉換爲對象的一個​​很好的例子。 – 2009-11-04 01:58:03

+0

這與他們的具體問題也是非常相關的,因爲他們的例子;) – 2009-11-04 01:58:56

+0

一個非常糟糕的例子,因爲System.Uri被認爲是與原始字符串表示和從絕對相對路徑轉換有關的問題。這就是每個抽象設計和API制定過程中發生的事情,你永遠無法從盒子中得到它,並且使用MSFT框架設計師需要很長的時間才能正確地使用它,並且常常導致比靜態方法更容易並且已知的複雜性本質上是功能性的。但是,這是'框架'和'設計指南'狂熱的方法總的問題。「 – 2009-11-04 09:22:57

0

他們都很好,只要你設計得很好(也就是說,你沒有自己的簽名,從隨着時間而改變)。

這些實用方法不會經常改變,因爲它們只做一件事。問題出現在您想要將更復雜的對象緊固到另一個對象時。如果他們中的一個需要改變或被替換,那麼如果你讓他們高度耦合,將會更困難。

由於這些實用方法不會經常改變,所以我會說這沒什麼問題。

我認爲如果您一遍又一遍地複製/粘貼相同的實用程序方法,情況會更糟糕。

這由Joshua布洛赫視頻How to design a good API and why it matters,解釋幾個概念設計API(這將是您的工具庫)時,要牢記。雖然他是公認的Java架構師,但內容適用於所有編程語言。

2

工具類沒問題,只要他們不違反設計原則。像使用核心框架類一樣愉快地使用它們。

這些類應該命名合理。真的,他們並不是那麼「實用」,而是本土課程所沒有提供的新興實體的一部分。

使用類似擴展方法的東西也可以用於將功能對齊到「正確」類。但是,它們可能會造成一些混淆,因爲擴展沒有與它們通常擴展的類一起打包,這並不理想,但仍然可以非常有用並且生成更簡潔的代碼。

2

您總是可以創建一個接口,並使用依賴注入來實現那些實現該接口而不是靜態類的類的實例。

問題變成真的值得嗎?在一些系統中,答案是肯定的,但在其他系統中,尤其是較小的答案中,答案可能不是。

+0

這也是我的建議。如果實用方法複雜或計算成本高昂,我會建議使用依賴注入將其作爲某種服務對象注入。否則我不會擔心。 – 2009-11-04 01:56:39

+0

注入不會消除依賴關係。它只是讓它更容易處理。 – OscarRyz 2009-11-04 01:58:48

+0

刪除**依賴關係的唯一方法是刪除它。我沒有看到你的觀點。 – 2009-11-04 02:00:48

1

我真的,真的試圖避免它們,但是我們是在開玩笑嗎?他們爬進每個系統。儘管如此,在給出的示例中,我將使用URL對象,然後公開該URL的各種屬性(協議,域,路徑和查詢字符串參數)。 近乎每次我想創建一個實用工具類的靜態,我可以通過創建一個對象來做這種工作來獲得更多的價值。

以類似的方式,我創建了很多自定義控件,內置了百分比,貨幣,電話號碼等的驗證。在此之前,我有一個解析器實用程序類,它具有所有這些規則,但它使得它更加簡潔,只需將控件放在已知基本規則的頁面上(因此只需要業務邏輯驗證即可添加)。

我仍然保留解析器工具類和這些控件隱藏該靜態類,但廣泛使用它(保持所有解析在一個容易找到的地方)。在這方面,我認爲有實用程序類是可以接受的,因爲它允許我應用「不要重複自己」,而使用控件或使用實用程序的其他對象獲得實例類的好處。

1

我同意其中的一些其他答案,它是維護一個有狀態對象的單個實例的經典單例,它應該被避免並且不一定是沒有狀態的實用程序類。我也同意裏德的觀點,即如果可能的話,將這些效用方法放在一個有意義的類中,並且在邏輯上懷疑這些方法會存在的地方。我想補充一點,通常這些靜態效用方法可能是擴展方法的很好候選者。

0

謹慎地使用它們,您希望儘可能多地將邏輯放入類中,這樣它們就不會變成數據容器。

但是,在同一時間你不能真正避免utilites,他們有時是必需的。

在這種情況下,我認爲沒關係。

僅供參考有system.web.httputility類,其中包含許多常見的http實用程序,您可能會發現有用。

1

這真的取決於上下文以及我們如何使用它。

實用程序類本身並不差。但是,如果我們以不好的方式使用它會變得糟糕。每種設計模式(尤其是Singleton模式)都可以很容易地變成反模式,對於Utility類也是如此。

在軟件設計中,我們需要在靈活性的簡單性之間取得平衡。如果我們要創建一個StringUtils,它只負責字符串操作:

  • 它違反了SRP(單一職責原則)嗎? - >沒有,這是開發人員將太多的責任投入到違反SRP的實用程序類中。
  • 「它不能使用DI框架注入」 - >是否StringUtils實現會有所不同?我們會在運行時切換其實現嗎?我們會嘲笑它嗎?當然不是。

=>實用程序類themselve並不差。這是開發商的錯,使它變得糟糕。

這一切都取決於上下文。如果你只是想創建一個只包含單一責任的實用程序類,並且只在模塊或圖層中私下使用。那麼你對它仍然很好。