新聞中心
審校 | 梁策 孫淑娟

創(chuàng)新互聯(lián)建站于2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站建設(shè)、做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元青縣做網(wǎng)站,已為上家服務(wù),為青縣各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792
概述
我們將研究如何通過(guò)Lombok的@Builder注解讓含有多個(gè)入?yún)⒌姆椒ǜ菀妆徽{(diào)用,從而提高可用性。
使用@Builder的簡(jiǎn)單方法
怎樣才能更靈活方便地調(diào)用多入?yún)⒎椒?請(qǐng)看下面的例子:
void method(@NotNull String firstParam, @NotNull String secondParam,
String thirdParam, String fourthParam,
Long fifthParam, @NotNull Object sixthParam) {
...
}
如果非空參數(shù)是可選的,那么有以下幾種調(diào)用方式:
method("A", "B", null, null, null, new Object());
method("A", "B", "C", null, 2L, "D");
method("A", "B", null, null, 3L, this);
...這個(gè)例子暴露了一些問(wèn)題,比如:
- 調(diào)用者必須知道修改哪個(gè)參數(shù)(例如,第一個(gè)調(diào)用方法如果改為第二個(gè),調(diào)用者必須知道要修改第五個(gè)為L(zhǎng)ong類型參數(shù))。
- 入?yún)㈨樞虿豢筛淖儭?/li>
- 需要傳入的參數(shù)名稱不可見。
從提供者的角度來(lái)看,如果要提供參數(shù)較少的方法則需要大量重載,如下:
void method(@NotNull String firstParam, @NotNull String secondParam, @NotNull Object sixthParam);
void method(@NotNull String firstParam, @NotNull String secondParam, String thirdParam, @NotNull Object sixthParam);
void method(@NotNull String firstParam, @NotNull String secondParam, String thirdParam, String fourthParam, @NotNull Object sixthParam);
void method(@NotNull String firstParam, @NotNull String secondParam, String thirdParam, String fourthParam, Long fifthParam, @NotNull Object sixthParam);
...
為了提高可用性且避免重復(fù)代碼,我們可以使用方法構(gòu)建器。Lombok項(xiàng)目已經(jīng)提供了一個(gè)注解,它可以使生成構(gòu)建器變得更簡(jiǎn)單。因此,上面的例子可以改造為以下方式:
@Builder(builderMethodName = "methodBuilder", buildMethodName = "call")
void method(@NotNull String firstParam, @NotNull String secondParam,
String thirdParam, String fourthParam,
Long fifthParam, @NotNull Object sixthParam) {
...
}
然后就可以這樣調(diào)用方法:
methodBuilder()
.firstParam("A")
.secondParam("B")
.sixthParam(new Object())
.call();
methodBuilder()
.firstParam("A")
.secondParam("B")
.thirdParam("C")
.fifthParam(2L)
.sixthParam("D")
.call();
methodBuilder()
.firstParam("A")
.secondParam("B")
.fifthParam(3L)
.sixthParam(this)
.call();
這樣一來(lái),方法的可讀性及靈活性都提高了。
- 默認(rèn)情況下,一個(gè)靜態(tài)方法的builder方法(獲得構(gòu)建器實(shí)例的方法)就是一個(gè)靜態(tài)方法。
- 默認(rèn)情況下,call()方法將拋出原方法的異常。
默認(rèn)值
在許多情況下,需要去為方法的入?yún)⒅付J(rèn)值,而Java與其他一些語(yǔ)言不同,它沒有語(yǔ)義來(lái)支持這一需求。因此,在大多數(shù)情況下,它都是通過(guò)方法重載來(lái)實(shí)現(xiàn)的,如下:
method() { method("Hello"); }
method(String a) { method(a, "builder"); }
method(String a, String b) { method(a, b, "world!"); }
method(String a, String b, String c) { ... acutal logic here ... } 當(dāng)使用Lombok builder時(shí),會(huì)在目標(biāo)類中生成一個(gè)構(gòu)建器類。這個(gè)構(gòu)建器類:
- 擁有與方法相同數(shù)量的屬性和參數(shù)。
- 有參數(shù)的set方法。
該類也可以手動(dòng)定義,這樣就可以為參數(shù)定義默認(rèn)值。上面的方法也就可以寫成:
@Builder(builderMethodName = "methodBuilder", buildMethodName = "call", builderClassName = "MethodBuilder")
method(String a, String b, String c) {
... acutal logic here ...
}
private class MethodBuilder {
private String a = "Hello";
private String b = "builder";
private String c = "world!";
}
有了這個(gè)補(bǔ)充,如果調(diào)用者沒有指定一個(gè)參數(shù),那么將使用構(gòu)建器類中定義的默認(rèn)值。
注意:在這種情況下,我們不需要在類中聲明該方法的所有入?yún)?,Lombok會(huì)自動(dòng)配置。
泛型方法
我們會(huì)有通過(guò)入?yún)⑷ザx返回類型的需求,例如:
publicT read(byte[] content, Class type) {...}
在這種情況下,builder類將是一個(gè)泛型類,但是builder方法將創(chuàng)建一個(gè)沒有約束類型的實(shí)例。請(qǐng)看下面的例子:
@Builder(builderMethodName = "methodBuilder", buildMethodName = "call", builderClassName = "MethodBuilder")
publicT read(byte[] content, Class type) {...}
在這種情況下,methodBuilder方法將創(chuàng)建一個(gè)沒有約束類型的MethodBuilder實(shí)例。這導(dǎo)致下面的代碼不會(huì)被編譯(入?yún)⒍x為Class,傳入Class):
methodBuilder()
.content(new byte[]{})
.type(String.class)
.call();
上述問(wèn)題可以通過(guò)強(qiáng)制轉(zhuǎn)換類型來(lái)解決:
methodBuilder()
.content(new byte[]{})
.type((Class)String.class)
.call();
這樣,它就可以通過(guò)編譯。但是這么使用,調(diào)用方法后返回的類型不是String,而是未知類型的泛型T。
String result = (String)methodBuilder()
.content(new byte[]{})
.type((Class)String.class)
.call();
那么,我們需要再將輸出結(jié)果進(jìn)行強(qiáng)制轉(zhuǎn)換。而我們最初的目的是提供一種方便調(diào)用者的方法,因此建議考慮下面的兩種解決方案之一。
覆蓋Builder方法
如上所述,問(wèn)題的根源在于builder方法在沒有傳入特定類型參數(shù)的情況下,創(chuàng)建了builder類的實(shí)例。所以我們可以在類中重載構(gòu)建器方法,并實(shí)例化一個(gè)指定類型的構(gòu)建器類:
@Builder(builderMethodName = "methodBuilder", buildMethodName = "call", builderClassName = "MethodBuilder")
publicT read(final byte[] content, final Class type) {...}
publicMethodBuilder methodBuilder(final Class type) {
return new MethodBuilder().type(type);
}
public class MethodBuilder{
private Classtype;
public MethodBuildertype(Class type) { this.type = type; return this; }
public T call() { return read(content, type); }
}
在這種情況下,調(diào)用者不需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,調(diào)用過(guò)程如下:
List result = methodBuilder(List.class)
.content(new byte[]{})
.call();
在setter方法中強(qiáng)制轉(zhuǎn)換
也可以在類型參數(shù)set方法中強(qiáng)轉(zhuǎn)構(gòu)建器實(shí)例類型:
@Builder(builderMethodName = "methodBuilder", buildMethodName = "call", builderClassName = "MethodBuilder")
publicT read(final byte[] content, final Class type) {...}
public class MethodBuilder{
private Classtype;
publicMethodBuilder type(final Class type) {
this.type = (Class)type;
return (MethodBuilder) this;
}
public T call() { return read(content, type); }
}
使用這種方式就不需要手動(dòng)定義構(gòu)建器方法。從調(diào)用者的角度來(lái)看,類型參數(shù)就像其他參數(shù)一樣直接傳入。
結(jié)論
在方法上使用@Builder可以帶來(lái)以下優(yōu)勢(shì):
- 提高了調(diào)用者的靈活性
- 在不寫重載方法的前提下,可以定義參數(shù)的默認(rèn)值
- 提高了方法調(diào)用的可讀性
- 可以通過(guò)同一個(gè)builder實(shí)例進(jìn)行類似的調(diào)用
需要注意的是,在某些情況下,使用方法構(gòu)建器會(huì)給提供者帶來(lái)不必要的復(fù)雜情況。各類方法構(gòu)建器的demo可參考GitHub上的信息。
譯者介紹
翟珂,社區(qū)編輯,目前在杭州從事軟件研發(fā)工作,做過(guò)電商、征信等方面的系統(tǒng),享受分享知識(shí)的過(guò)程,充實(shí)自己的生活。
原文標(biāo)題:??Method Builder With Lombok @Builder??,作者:Daniel Buza
文章名稱:使用Lombok的@Builder注解實(shí)現(xiàn)構(gòu)造器模式
新聞來(lái)源:http://www.5511xx.com/article/dpiodop.html


咨詢
建站咨詢
