装饰者模式如何拯救了我的一天
在工作中,我正在處理龐大的Java代碼庫,該代碼庫是由許多不同的開發(fā)人員在15年的時間里開發(fā)的。 并不是所有的事情都由書來完成,但是同時我通常沒有機會重構遇到的每一個奇怪之處。
盡管如此,仍可以每天采取提高代碼質量的措施。 今天就像那樣……
總覽
由于已經 存在 大量 教程 ,因此本文的目的不是教授裝飾器模式。 相反,它提供了一個現(xiàn)實生活中的示例,說明它如何派上用場并節(jié)省了一天的時間。
情況
我們的UI包含Swing的JEdi??torPanes ,用于顯示HTML。 與各種鏈接的交互(例如,懸停和單擊)觸發(fā)以下一個或多個響應:
對于所有窗格,這些響應都不相同。 其中有一些需求部分不同。 (如果您知道裝飾器模式,那么您會看到它的去向。)
所以問題是:您如何實施這些響應?
一種可配置類的解決方案
您可以將所有這些都放在一個類中,該類實現(xiàn)HyperlinkListener并使用標志來(取消激活)不同的響應。
這個課真是地獄! 是的,地獄 就這么簡單。
首先,它將是巨大的。 而且,其本質上不相關的職責之間可能以某種方式有些奇怪的依賴。這種規(guī)模和這些關系將使編寫和測試變得更加困難,甚至使理解和修改變得更加困難。
(順便說一句,造成混亂的根本原因是AllInOneHyperlinkListener違反了單一職責原則 。由于這篇文章已經足夠長了,因此我將不做詳細介紹。)
繼承的解決方案
無論如何,我很幸運沒有發(fā)現(xiàn)自己正在面對一個龐然大物的聽眾。 取而代之的是,我發(fā)現(xiàn)了一個小的類層次結構,這些類將這些職責劃分為它們( HL是HyperlinkListener的縮寫):
通過更新窗格的內容或打開外部瀏覽器/應用程序來處理URL
這看起來更好,不是嗎? 好…
首先,某些班級仍然要承擔幾項責任。 沒有真正的理由解釋為什么日志和更改游標應該由同一類完成。 (我只能猜測,這種結構會隨著時間的推移而有機地增長,而沒有任何更深層次的設計。)因此,問題較小,但尚未消失。
它也顯示在班級名稱中。 以上內容已經過改進,以提高可讀性。 原始文檔中充滿了Default , Simple和其他非信息。 這個名字甚至是誤導性的名字都不是簡單的疏忽。 它們是缺乏凝聚力的自然結果。
但是通過更深層次的管理,這些問題本來可以得到緩解。 六個類可以各自實現(xiàn)一件事。 但這也不會幫助我。
不,此解決方案的真正問題是模擬的靈活性。 看起來您可以選擇,但實際上您不能。 看看當事情改變時會發(fā)生什么。
改變
我們慢慢地從搖擺移動到JavaFX的,我想以取代FX JEdi??torPane中” 的WebView 。 (實際上,將HyperlinkListeners放入WebView有點麻煩,但我將在另一篇文章中再討論。)WebView已經完成了上述某些操作,因此這是新偵聽器具有的更新響應列表。觸發(fā):
在這里,整個類系統(tǒng)變得毫無用處。 (至少因為我不愿意讓監(jiān)聽者對隱身控件進行2.和3.。)在這一點上,很明顯,職責混在一起了。 我仍然需要其中一些,但不是全部,而且由于它們之間沒有階級界限,所以我處于全有或全無的情況。
裝飾圖案的救援
因此,當我在考慮要混合和匹配現(xiàn)有功能的程度時,它最終使我受了折磨(并且比預期的要晚得多):這正是裝飾器模式的目的!
裝飾圖案
就像我說的,我不會詳細解釋這種模式,但是基本思想是:
當有一個接口,不同的實現(xiàn)可以提供不同的功能時,請讓每個實現(xiàn)獨立運行。 但是要實現(xiàn)它們,以便在工作中的某個時刻,他們將控制權移交給同一接口的另一個實例。
如果一個這樣的實現(xiàn)調用另一個,并使用該結果來計算自己的實現(xiàn),則兩者都可以做自己的事情,但是效果會重疊。 第二個實例的結果仍然存在,但是第一個實例有些改變。 因此,據(jù)說第一個裝飾第二個。
這可以在更多實例中進行,每個實例都裝飾前者。 應該將其視為分層系統(tǒng),其中每個裝飾器向整體添加另一層行為。
行動中
現(xiàn)在方法很清楚:我將上述功能重構為不同的裝飾器,例如LoggingHyperlinkListenerDecorator和ServiceRequestHandlingHyperlinkListenerDecorator 。
然后,我刪除了原始類,并用正確的裝飾器組合替換了它們的用途。 最終,我了解了新功能并選擇了正確的裝飾器。 用Java 8可以做到這一點,但是為了簡單起見,讓我們在這里使用構造函數(shù):
將裝飾器放在一起
// use a lambda expression to create the initial listener // which does nothing HyperlinkListener listener = event -> {}; // these decorators first do their own thing and then call the // decorated listener (the one handed over during construction); // in the end, the last added decorator will act first listener = new ExternalApplicationOpeningHyperlinkListenerDecorator(listener); listener =new BrowserOpeningHyperlinkListenerDecorator(listener); listener =new ServiceRequestHandlingHyperlinkListenerDecorator(listener); listener =new LoggingHyperlinkListenerDecorator(listener);除了樣板外,很明顯這里發(fā)生了什么。 首先,在我們確定服務請求并處理它們之前,將進行日志記錄。 如果可能,將在瀏覽器中打開其他任何內容; 否則,我們會將其交給一些外部應用程序。
效果
您馬上就可以看到對代碼的積極影響。 首先,每個班級都有一個非常簡單的責任。 這導致了簡短易懂的課程。 他們的名字通常是當場就正確地告訴您他們在做什么。 另外,由于每個單元中發(fā)生的事情更少,因此可測試性也提高了。
此外,將裝飾器放在一起的地方更能揭示其意圖。 您不必檢查實例化的ServiceRequestHandlingHyperlinkListener及其超類即可了解偵聽器的確切功能。 取而代之的是,您僅查看裝飾列表,看看會發(fā)生什么。
最后但并非最不重要的一點是,它使代碼為將來的更改做好了準備。 現(xiàn)在很明顯如何實現(xiàn)新的偵聽器功能。 對于繼承的類,您必須想知道在何處放置新功能,以及新功能如何影響該類的現(xiàn)有用法。 現(xiàn)在,您只需要實現(xiàn)第um裝飾器并在需要的地方添加它即可。
反射
這個真實的例子展示了裝飾器模式的應用如何使代碼更易于閱讀,測試和更改。
當然,這不是自動的。 該模式只能在確實使代碼更整潔的地方使用。 但是要決定這一點,您必須了解它并且必須能夠推理其影響。 我希望這篇文章對此有所幫助。
非常感謝Wikipedia的Benjah ,他創(chuàng)造了 Vaska復雜建筑 的美麗形象并將其發(fā)布到公共領域。
翻譯自: https://www.javacodegeeks.com/2015/01/how-the-decorator-pattern-saved-my-day.html
總結
以上是生活随笔為你收集整理的装饰者模式如何拯救了我的一天的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云监控电脑版(云监控电脑版下载安装)
- 下一篇: 电脑系统优化网站推荐(电脑优化软件推荐)