高频变压器_变压器图案
高頻變壓器
Transformer模式是Java(以及可能僅具有使用場(chǎng)所差異和不變參數(shù)類型的其他OO語言)的設(shè)計(jì)模式,可幫助子類型層次結(jié)構(gòu)內(nèi)的對(duì)象將自己流暢地轉(zhuǎn)換為任何類型的對(duì)象。
語境
我一直在關(guān)注與Jim Laskey發(fā)行的JDK-8203703有關(guān)的OpenJDK線程( 9月18-21日 , 11月12-13日, 11月13-30日, 12月3-4日 ),然后我想到了一個(gè)主意。 讓我回顧一下討論的相關(guān)部分。
String.transform的建議
根據(jù)JDK-8203703的提案可歸結(jié)為以下新增內(nèi)容:
public final class String implements /*...*/ CharSequence {// ...public <R> R transform(Function<? super String, ? extends R> f) {return f.apply(this);}// ... }如您所見,此方法本身僅調(diào)用給定的Function即可。 但是,它對(duì)于鏈接實(shí)用程序方法非常有用,例如Apache Commons的 StringUtils中的方法:
String result = string.toLowerCase().transform(StringUtils::stripAccents).transform(StringUtils::capitalize);通常,我們必須寫:
String result = StringUtils.capitalize(StringUtils.stripAccents(string.toLowerCase()));考慮CharSequence.transform
在某個(gè)時(shí)候,艾倫·貝特曼(Alan Bateman) 提出了 transform CharSequence中的transform定義為以下問題:
<R> R transform(Function<? super CharSequence, ? extends R> f)這將具有能夠在任何CharSequence上應(yīng)用基于CharSequence的實(shí)用程序方法(例如StringUtils.isNumeric )的好處,例如:
boolean isNumeric = charSequence.transform(s -> StringUtils.defaultIfBlank('0')).transform(StringUtils::isNumeric);但是,正如RémiForax 指出的那樣 ,此簽名的問題在于:
- 如果它是由String 繼承的:大多數(shù)實(shí)用程序方法都將String作為參數(shù)–這樣的方法將不起作用(例如StringUtils :: capitalize ),
- 如果它被String 覆蓋 :由于以下原因,無法進(jìn)行有用的覆蓋:
- Function<? super String, R>
結(jié)果, CharSequence.transform的主題已被刪除。
問題
綜上所述,問題在于能夠進(jìn)行轉(zhuǎn)換 :
- 一個(gè)CharSequence ,使用Function即需要CharSequence或Object ( ? super CharSequence ),
- 一個(gè)String ,使用接受String或其任何父類型( ? super String )的Function 。
當(dāng)我在這里查看這些下 限時(shí) ,我意識(shí)到我已經(jīng)看到了這種問題(參見Filterer Pattern )。
因此,這個(gè)問題歸結(jié)為:如何協(xié)變地指定Function的反 變界。
解
Java不支持逆變參數(shù)類型 ,并且其語法也不提供在單個(gè)聲明中協(xié)變( ? extends )指定逆變( ? super )綁定的方法。 然而,有可能做到這一點(diǎn)在兩個(gè)分開的宣言,通過中間輔助類型的裝置。
假設(shè)我們要為泛型Function<? super T, ? extends R> Function<? super T, ? extends R> Function<? super T, ? extends R> ,我們需要:
- 將上面的Function參數(shù)移動(dòng)到參數(shù)為T的輔助接口中 ,
- 將此輔助接口與上限 ( ? extends T )一起用作返回類型。
變壓器接口
我定義了這樣的幫助程序接口(我稱之為Transformer ),如下所示:
@FunctionalInterface interface Transformer<T> {<R> R by(Function<? super T, ? extends R> f); }可轉(zhuǎn)換的接口
定義了Transformer ,我們可以定義以下稱為Transformable基本接口:
interface Transformable {Transformer<?> transformed(); }該接口本身并不能做很多事情,但我將其視為以下方面的規(guī)范 :
- 子類型實(shí)現(xiàn)器 :提醒他們使用適當(dāng)?shù)纳舷薷采w已transformed方法,并加以實(shí)現(xiàn),
- 子類型用戶 :提醒他們可以調(diào)用transformed().by(f) 。
總結(jié)起來,這對(duì)( Transformer & Transformable )讓我們替換:
- obj.transform(function)
- 使用: obj.transformed().by(function)
樣例實(shí)施
回到String之前,讓我們看看實(shí)現(xiàn)這兩個(gè)接口有多么容易:
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);} }如您所見,所需要的只是對(duì)transform的方法引用 。
transform方法被設(shè)為私有,因此當(dāng)子類型定義自己的(適當(dāng)?shù)?#xff0c; 下界 ) transform時(shí),它們之間不會(huì)發(fā)生沖突。
上下文中的解決方案
上下文中的實(shí)現(xiàn)
它如何應(yīng)用于CharSequence和String ? 首先,我們將CharSequence擴(kuò)展為Transformable :
public interface CharSequence extends Transformable {// ...@OverrideTransformer<? extends CharSequence> transformed();// ... }然后,我們transformed在String實(shí)現(xiàn)transformed ,返回對(duì)public transform方法( 在JDK 12中添加 )的方法引用:
public final class String implements /*...*/ CharSequence {// ...@Overridepublic Transformer<String> transformed() {return this::transform;}// ... }請(qǐng)注意,我們對(duì)transformed的返回類型進(jìn)行了協(xié)變更改: Transformer<? extends CharSequence> Transformer<? extends CharSequence> → Transformer<String> 。
相容性風(fēng)險(xiǎn)
我認(rèn)為添加CharSequence.transformed的兼容性風(fēng)險(xiǎn)很小。 僅對(duì)于那些已經(jīng)具有無參數(shù)transformed方法的CharSequence子類,這可能會(huì)破壞向后兼容性(這似乎不太可能)。
上下文中的用法
對(duì)于使用String不會(huì)改變,因?yàn)橛泻粲鯖]有一點(diǎn)transformed().by()在transform()
但是,通用CharSequence的用法將需要訴諸transformed().by()因?yàn)樗赡苡性S多實(shí)現(xiàn),因此transform方法必須是private :
boolean isNumeric = charSequence.transformed().by(s -> StringUtils.defaultIfBlank('0')).transformed().by(StringUtils::isNumeric);性能
如果您不熟悉JVM (最常表示HotSpot )及其JIT編譯器的工作方式,那么您可能會(huì)懷疑這種額外對(duì)象的明顯創(chuàng)建( Transformer in transformed )是否不會(huì)影響性能。
幸運(yùn)的是,由于進(jìn)行了轉(zhuǎn)義分析 *和標(biāo)量替換 ,因此該對(duì)象永遠(yuǎn)不會(huì)在堆上分配。 答案是:不,不會(huì)。
* 此Wikipedia條目包含錯(cuò)誤的陳述:“ 因此,編譯器可以安全地在堆棧上分配兩個(gè)對(duì)象。 ”正如 AlekseyShipilёv解釋的那樣 ,Java不會(huì)在堆棧上分配整個(gè)對(duì)象。
基準(zhǔn)測(cè)試
如果您需要證明,這里有一些基準(zhǔn)(使用AlekseyShipilёv出色的JMH基準(zhǔn)線束 )。 因?yàn)槲也荒?#xff08;容易),添加必要的方法,以String ,我創(chuàng)建了一個(gè)簡(jiǎn)單的包裝過String ,并實(shí)現(xiàn)了在它之上的標(biāo)桿。
基準(zhǔn)測(cè)試toLowerCase()操作:
- 在兩個(gè)字符串上:
- "no change" (無操作)
- "Some Change"
- 使用三種通話類型:
- 直接(基準(zhǔn))
- transform()
- transformed().by()
您可以在GitHub gist中找到此基準(zhǔn)測(cè)試的完整源代碼。
結(jié)果如下(在Oracle JDK 8上運(yùn)行,耗時(shí)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如您所見,對(duì)于這兩個(gè)字符串,這三種調(diào)用類型之間沒有性能差異。
摘要
我意識(shí)到, Transformable可能過于“奢侈”,以致于無法真正將其納入JDK。 實(shí)際上,即使僅由CharSequence和String返回的Transformer也不值得。 這是因?yàn)閷?duì)CharSequence的一元運(yùn)算似乎并不常見(例如StringUtils僅包含少數(shù)幾個(gè))。
但是,我發(fā)現(xiàn)“ Transformer和“ Transformable的基本概念很誘人。 因此,我希望您喜歡閱讀,并且在某些情況下會(huì)發(fā)現(xiàn)它很有用
翻譯自: https://www.javacodegeeks.com/2019/02/transformer-pattern.html
高頻變壓器
總結(jié)
以上是生活随笔為你收集整理的高频变压器_变压器图案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 男朋友用英语怎么说 如何用英语表达男朋友
- 下一篇: stripe pay_J2Pay –简介