日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 8的装饰器模式

發布時間:2023/12/3 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 8的装饰器模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在最近的一篇文章中,我描述了裝飾器模式如何拯救了我的一天。 我給出了一個小代碼段,其中包含創建裝飾器的最簡單方法,但承諾Java 8會有更好的方法。

這里是:

用Java 8裝飾

HyperlinkListener listener = this::changeHtmlViewBackgroundColor; listener = DecoratingHyperlinkListener.from(listener).onHoverMakeVisible(urlLabel).onHoverSetUrlOn(urlLabel).logEvents().decorate(l -> new OnActivateHighlightComponent(l, urlLabel)).decorate(OnEnterLogUrl::new);

我將在文章的其余部分中說明如何到達那里。

我在GitHub上創建了一個小樣本項目 ,我將從這里重復引用。 我只建議您檢查一下它,因為它提供了更多詳細信息。 它是公共領域 ,因此可以不受限制地使用該代碼。

為了繼續我的上一篇文章,它使用Swing的HyperlinkListener作為裝飾的基礎。 由于該接口不是通用接口,并且僅具有一個僅帶有一個參數的方法(對于lambda表達式而言非常好!),因此具有使其保持簡單的附加優點。

總覽

像其他帖子一樣,該帖子也沒有嘗試教授模式本身。 (不過,我找到了另一個很好的解釋 。)相反,它推薦了一種在Java 8中實現它的方法,以使其使用起來非常方便。 因此,該帖子嚴重依賴Java 8功能,尤其是默認方法和lambda表達式 。

這些圖只是草圖,并省略了許多細節。 更完整的是容易找到的 。

香草

在模式的通常實現中,存在一個接口(上面稱為Component ),該接口將通過“常規”類以及所有裝飾器以常規方式實現。

抽象裝飾器類

裝飾器通常從中間抽象基類( AbstractDecorator )繼承,從而簡化了實現。 它使用另一個組件作為構造函數參數,并通過將所有調用轉發給接口來實現接口本身。 因此,裝飾組件的行為不變。

現在由子類來實際更改它。 他們通過有選擇地重寫那些他們想改變其行為的方法來做到這一點。 這通常包括對裝飾組件的調用。

裝飾器的創建

通常,不使用任何特殊技術來創建裝飾器。 只是簡單的構造函數。 使用復雜的裝飾器,您甚至可以使用工廠。

我是靜態構造方法的忠實擁護者,因此我使用它們并將構造方法設為私有。 為了使這些方法的調用者不了解細節,我將這些方法的返回類型聲明為Component ,而不是裝飾器的更詳細類型。 例如,這可以在LogEventsToConsole中看到。

我的建議改變了裝飾器的創建方式。

使用Java 8

要使用Java 8的所有功能,我建議為所有裝飾器添加一個特殊的接口DecoratingComponent 。 裝飾器的抽象超類實現了該接口,但像以前一樣,僅保留對Component的引用。

重要的是要注意,由于新接口的定義(請參閱下文),混凝土裝飾器沒有任何變化。 它們在模式的兩種實現中都是完全相同的。 抽象類實際上也沒有任何變化(請參見下文),因此切換到該解決方案不會產生明顯的成本。

新介面

新接口DecoratingComponent擴展了基本組件接口,并為裝飾器提供了工廠方法。 這些是靜態或默認/防御程序方法(因此它們已經實現,如果可以的話將是最終方法),并且不應聲明任何抽象方法。 這樣,新接口不會在繼承樹后面的實現上增加額外的負擔。

關于以下代碼示例:通用示例僅是為該帖子創建的。 涉及超鏈接偵聽器的對象來自演示應用程序 。 最值得注意的是DecoratingHyperlinkListener ( 到源文件的鏈接 ),它擴展了Swing的HyperlinkListener 。

方法

該接口本身實際上非常簡單,由三種類型的方法組成。

適配器

若要快速從Component移至DecoratingComponent ,接口應具有靜態方法,該方法采用第一個方法,然后返回后者。 由于DecoratingComponent擴展了Component且未添加任何抽象方法,因此這很簡單。 只需創建一個匿名實現,并將所有調用轉發到已適配的component 。

通用方法如下所示:

靜態適配器方法

static DecoratingComponent from(Component component) {DecoratingComponent adapted = new DecoratingComponent() {@Overridepublic SomeReturn someMethod(SomeArgument argument) {return component.someMethod(argument);}// ... more methods here ...};return adapted; }

在DecoratingHyperlinkListener情況下,它要容易得多,因為它是一個功能接口,因此可以使用lambda表達式:

'DecoratingHyperlinkListener'中的靜態適配器方法

static DecoratingHyperlinkListener from(HyperlinkListener listener) {return event -> listener.hyperlinkUpdate(event); }

通用裝飾

這是接口的基本方法:

default DecoratingComponent decorate(Function<? super DecoratingComponent, ? extends DecoratingComponent>decorator) {return decorator.apply(this); }

它從一個裝飾組件到另一個裝飾組件接受一個函數作為參數。 它將功能應用于自身以創建裝飾的實例,然后將其返回。

可以在整個代碼中使用此方法,以一種簡單易讀的方式裝飾任何組件:

用'DecoratingComponent'裝飾

Component some = ...; DecoratingComponent decorated = DecoratingComponent// create an instance of 'DecoratingComponent' from the 'Component'.from(some)// now decorate it.decorate(component -> new MyCoolComponentDecorator(component, ...));// if you already have an instance of 'DecoratingComponent', it get's easier decorated = decorated.decorate(component -> new MyBestComponentDecorator(component, ...));// constructor references are even clearer (but cannot always be used) decorated = decorated.decorate(MyBestComponentDecorator::new);

混凝土裝飾

您還可以添加使用具體裝飾器裝飾實例的方法:

“ DecoratingHyperlinkListener”中的混凝土裝飾

default DecoratingHyperlinkListener logEvents() {return LogEventsToConsole.decorate(this); }default DecoratingHyperlinkListener onHoverMakeVisible(JComponent component) {return OnHoverMakeComponentVisible.decorate(this, component); }

它們使裝飾非常簡潔易讀:

用'DecoratingComponent'裝飾

DecoratingComponent decorated = ... decorated = decorated.logEvents();

但是,是否應真正添加這些方法仍有待商de。 盡管它們非常方便,但是當它們創建循環依賴關系時,可以對它們進行強烈的爭論。 裝飾者不僅知道接口(它們是通過抽象超類間接實現的),現在接口也知道其實現。 通常,這是刺激性的代碼氣味。

最終召集尚未結束,但我建議采取務實的中間方法。 我讓接口知道存在于同一包中的實現。 這將是通用的,因為它們沒有引用其余代碼中的任何具體內容。 但是我不會讓它知道我在系統深處創建的每個瘋狂裝飾器。 (當然,除非將其稱為the_kraken,否則我不會將所有這些裝飾器都添加到同一包中。)

為什么需要額外的接口?

是的,是的,所有那些Java 8功能都非常不錯,但是您不能簡單地將這些方法添加到AbstractDecorator嗎? 好問題!

當然,我可以在這里添加它們。 但是由于兩個原因,我不喜歡這種解決方案。

單一責任原則

首先,這將模糊類的職責。 新接口負責裝飾Component實例,抽象超類負責使裝飾器易于實現。

這些不是相同的事物,并且由于相同的原因它們不會改變。 每當必須包含新的裝飾器時,新的接口就可能更改。 每當Component更改時,抽象類都會更改。

類型層次結構

如果將這些方法添加到AbstractDecorator ,則只能在此類實例上調用它們。 因此,所有裝飾器都必須從該類繼承,這限制了將來實現的范圍。 誰知道,也許出現了一些非常好的理由,為什么另一個類不能成為AbstractDecorator 。

更糟糕的是,所有裝飾器都必須公開一個事實,即它們是AbstractDecorator 。 突然有一個抽象類,它只是為了簡化實現而創建的,它遍及整個代碼庫。

其他差異

除了引入新接口之外,模式的變化不會有太大變化。

對抽象裝飾器類的更改

如果可以訪問該類,則應讓它實現DecoratingComponent而不是Component 。 由于沒有引入新的抽象方法,因此不需要進一步的更改。 上面的UML圖中顯示了這一點。

如果您不能更改類,則裝飾器將僅實現Component 。 這將使您避免使用其構造函數來創建將組件映射到裝飾組件的函數。 由于需要將該函數作為decorate方法的參數,因此必須將該方法更改為如下所示:

通用裝飾

// note the more general second type of the 'Function' interface default DecoratingComponent decorate(Function<? super DecoratingComponent, ? extends Component> decorator) {// create the decorated instance as beforeComponent decorated = decorator.apply(this);// since it is no 'DecoratingComponent' use 'from' to turn it into onereturn from(decorated); }

裝飾的變化

無需更改這些類。 當然,除非您是使用靜態工廠方法的那些瘋狂的人之一。 比您必須確保它們將其返回類型聲明為DecoratingComponent否則您將處于與抽象超類無法實現新接口的情況相同的情況。 如果您不能更改裝飾器類,則此處使用相同的解決方案。

因此,讓我們從上方再次查看代碼段:

用Java 8裝飾

// create a 'HyperlinkListener' with a method reference HyperlinkListener listener = this::changeHtmlViewBackgroundColor; // decorate that instance with different behaviors // (note that each call actually returns a new instance // so the result has to be assigned to a variable) listener = DecoratingHyperlinkListener// adapt the 'HyperlinkListener' to be a 'DecoratingHyperlinkListener'// (looks better if it is not on its own line).from(listener)// call some concrete decorator functions.onHoverMakeVisible(urlLabel).onHoverSetUrlOn(urlLabel).logEvents()// call the generic decorator function with a lambda expression.decorate(l -> new OnActivateHighlightComponent(l, urlLabel))// call the generic decorator function with a constructor reference.decorate(OnEnterLogUrl::new);

反射

我們了解了如何使用Java 8的靜態和默認接口方法為裝飾器模式創建流暢的API。 它使代碼同時更加簡潔和可讀性,同時又不干擾模式的機制。

正因為如此,我們使用默認的方法來創建特質有關其作者Brian Goetz寫道 :

了解默認方法的關鍵是,主要的設計目標是接口演變 ,而不是“將接口轉變為(中等)特性”

對不起,布萊恩,這太誘人了。 ;)

對裝飾器模式有一些見解? 想要改善我的想法還是批評它? 然后發表評論! 并且不要忘記在GitHub上檢查代碼 。

翻譯自: https://www.javacodegeeks.com/2015/01/the-decorator-pattern-with-java-8.html

總結

以上是生活随笔為你收集整理的Java 8的装饰器模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。