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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

变压器图案

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 变压器图案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Transformer模式是Java(以及可能僅具有使用場所差異和不變參數類型的其他OO語言)的設計模式,可幫助子類型層次結構內的對象將自己流暢地轉換為任何類型的對象。

語境

我一直在關注與Jim Laskey發行的JDK-8203703相關的OpenJDK線程( 9月18-21日 , 11月12-13日, 11月13-30日, 12月3-4日 ),然后我想到了一個主意。 讓我回顧一下討論的相關部分。

String.transform的建議

根據JDK-8203703的提案可歸結為以下新增內容:

public final class String implements /*...*/ CharSequence {// ...public <R> R transform(Function<? super String, ? extends R> f) {return f.apply(this);}// ... }

如您所見,此方法僅自身調用給定的Function即可。 但是,它對于鏈接實用程序方法非常有用,例如Apache Commons的 StringUtils中的方法:

String result = string.toLowerCase().transform(StringUtils::stripAccents).transform(StringUtils::capitalize);

通常,我們必須寫:

String result = StringUtils.capitalize(StringUtils.stripAccents(string.toLowerCase()));

考慮CharSequence.transform

在某個時候,艾倫·貝特曼(Alan Bateman) 提出了在CharSequence中潛在定義transform 的問題 :

<R> R transform(Function<? super CharSequence, ? extends R> f)

這將具有能夠在任何CharSequence上應用基于CharSequence的實用程序方法(例如StringUtils.isNumeric )的好處,例如:

boolean isNumeric = charSequence.transform(s -> StringUtils.defaultIfBlank('0')).transform(StringUtils::isNumeric);

但是,正如RémiForax所指出的 ,此簽名的問題在于:

  • 如果它是由String 繼承的:大多數實用程序方法都將String作為參數–這樣的方法將不起作用(例如StringUtils :: capitalize ),
  • 如果它被String 覆蓋 :由于以下原因,無法進行有用的覆蓋:
    • Function<? super String, R>

結果, CharSequence.transform的主題已被刪除。

問題

總而言之,問題在于能夠進行轉換 :

  • 一個CharSequence ,使用Function即需要CharSequence或Object ( ? super CharSequence ),
  • 一個String ,使用接受String或其任何父類型( ? super String )的Function 。

當我在這里查看這些下 限時 ,我意識到我已經看到了這種問題(參見Filterer Pattern )。

因此,這個問題歸結為:如何協變地指定Function的反 變界。

Java不支持逆變參數類型 ,并且它的語法也沒有提供一種方法來協變( ? extends )指定在單個聲明中綁定的逆變( ? super )。 然而,有可能做到這一點在兩個分開的宣言,通過中間輔助類型的裝置。

假設我們要為泛型Function<? super T, ? extends R> Function<? super T, ? extends R> Function<? super T, ? extends R> ,我們需要:

  • 將上面的Function參數移動到參數為T的輔助接口中 ,
  • 將此輔助接口與上限 ( ? extends T )一起用作返回類型。

變壓器接口

我定義了這樣的幫助程序接口(我稱之為Transformer ),如下所示:

@FunctionalInterface interface Transformer<T> {<R> R by(Function<? super T, ? extends R> f); }

可轉換的接口

定義了Transformer ,我們可以定義以下稱為Transformable基本接口:

interface Transformable {Transformer<?> transformed(); }

該接口本身并不能做很多事情,但我將其視為以下方面的規范 :

  • 子類型實現者 :它提醒他們使用適當的上限覆蓋已transformed方法,并加以實現,
  • 子類型用戶 :提醒他們可以調用transformed().by(f) 。

總結起來,這對( Transformer & Transformable )讓我們替換:

  • obj.transform(function)
  • 使用: obj.transformed().by(function)

樣例實施

回到String之前,讓我們看看實現這兩個接口有多么容易:

class Sample implements Transformable {@Overridepublic Transformer<Sample> transformed() {return this::transform; // method reference}private <R> R transform(Function<? super Sample, ? extends R> f) {return f.apply(this);} }

如您所見,所需要的只是對transform的方法引用 。

transform方法被設為私有,因此當子類型定義自己的(適當地, 下界 ) transform時,它們之間不會發生沖突。

上下文中的解決方案

上下文中的實現

它如何應用于CharSequence和String ? 首先,我們將CharSequence擴展為Transformable :

public interface CharSequence extends Transformable {// ...@OverrideTransformer<? extends CharSequence> transformed();// ... }

然后,我們transformed在String實現transformed ,返回對public transform方法的方法引用(已在JDK 12中添加 ):

public final class String implements /*...*/ CharSequence {// ...@Overridepublic Transformer<String> transformed() {return this::transform;}// ... }

請注意,我們對transformed的返回類型進行了協變更改: Transformer<? extends CharSequence> Transformer<? extends CharSequence> → Transformer<String> 。

相容性風險

我認為添加CharSequence.transformed的兼容性風險很小。 僅對于那些已經具有無參數transformed方法的CharSequence子類,它可能會破壞向后兼容性(這似乎不太可能)。

上下文中的用法

對于使用String不會改變,因為有呼吁沒有一點transformed().by()在transform()

但是,通用CharSequence的用法將需要訴諸transformed().by()因為它可能有很多實現,因此transform方法必須是private :

boolean isNumeric = charSequence.transformed().by(s -> StringUtils.defaultIfBlank('0')).transformed().by(StringUtils::isNumeric);

性能

如果您不熟悉JVM (最常表示HotSpot )及其JIT編譯器的工作方式,那么您可能想知道這種明顯的額外對象創建( Transformer in transformed )是否不會影響性能。

幸運的是,由于有了轉義分析 *和標量替換 ,該對象從未在堆上分配。 答案是:不會,不會。

* 此Wikipedia條目包含錯誤的陳述:“ 因此,編譯器可以安全地在堆棧上分配這兩個對象。 ”正如 AlekseyShipilёv解釋的那樣 ,Java不會在堆棧上分配整個對象。

基準測試

如果您需要證明,這里有一些基準(使用AlekseyShipilёv出色的JMH基準線束 )。 因為我不能(容易),添加必要的方法,以String ,我創建了一個簡單的包裝過String ,并實現了在它之上的標桿。

基準測試toLowerCase()操作:

  • 在兩個字符串上:
  • "no change" (無操作)
  • "Some Change"
  • 使用三種通話類型:
  • 直接(基準)
  • transform()
  • transformed().by()

您可以在GitHub gist中找到此基準測試的完整源代碼。

結果如下(在Oracle JDK 8上運行,花費了50分鐘):

Benchmark (string) Mode Cnt Score Error UnitsTransformerBenchmark.baseline no change avgt 25 22,215 ± 0,054 ns/op TransformerBenchmark.transform no change avgt 25 22,540 ± 0,039 ns/op TransformerBenchmark.transformed no change avgt 25 22,565 ± 0,059 ns/opTransformerBenchmark.baseline Some Change avgt 25 63,122 ± 0,541 ns/op TransformerBenchmark.transform Some Change avgt 25 63,405 ± 0,196 ns/op TransformerBenchmark.transformed Some Change avgt 25 62,930 ± 0,209 ns/op

如您所見,對于這兩個字符串,這三種調用類型之間沒有性能差異。

摘要

我意識到, Transformable可能太“奢侈”了,無法真正將其納入JDK。 實際上,即使僅由CharSequence和String返回的Transformer也不值得。 這是因為對CharSequence的一元運算似乎并不常見(例如StringUtils僅包含少數幾個)。

但是,我發現“ Transformer和“ Transformable的基本概念很誘人。 因此,我希望您喜歡閱讀,并在某些情況下會發現它很有用

翻譯自: https://www.javacodegeeks.com/2019/02/transformer-pattern.html

總結

以上是生活随笔為你收集整理的变压器图案的全部內容,希望文章能夠幫你解決所遇到的問題。

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