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

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


咨詢
建站咨詢
