學(xué)了這個,三歪再也不想寫各種setter了
今天又來給大家吹一下逼。
三歪在公司里邊也看了不少的系統(tǒng)了,看到結(jié)構(gòu)清晰、代碼清晰的系統(tǒng)時會贊嘆能寫出這種代碼的人是真的牛逼??吹絹y七八糟的代碼又不寫注釋的時候也會吐槽:“這寫的是啥啊”
多看別人的代碼,總會有不同的發(fā)現(xiàn)和體會。
最近看別人項目的時候,發(fā)現(xiàn)會有這種寫法:
MessageTask?task?=?MessageTask.builder()
??.content("關(guān)注?Java3y?吧?>>?")
??.messageId(String.valueOf(ThreadLocalRandom.current().nextLong()))
??.taskId("3y")
??.taskName("一起來玩")
??.build();
System.out.println(task.toString());
看代碼其實很容易看出它在干嘛,就是在創(chuàng)建MessageTask這個對象。
平時我們初學(xué)的時候,如果要創(chuàng)建這個對象會怎么寫?一般會有兩種方法:
- 將屬性配在構(gòu)造函數(shù)上,然后直接調(diào)構(gòu)造器,傳入?yún)?shù)
- 調(diào)用多個
set方法
//?構(gòu)造器傳入屬性
MessageTask?messageTask?=?new?MessageTask("3y",?"關(guān)注?Java3y?吧?>>",?
??????????????????????????????????????????String.valueOf(ThreadLocalRandom.current().nextLong()),?"一起來玩");
//?調(diào)用各種的set方法
MessageTask?messageTask?=?new?MessageTask();
messageTask.setTaskId("3y");
messageTask.setContent("關(guān)注?Java3y?吧?>>");
messageTask.setMessageId(String.valueOf(ThreadLocalRandom.current().nextLong()));
messageTask.setTaskName("一起來玩");
日常使用的話,應(yīng)該是多次調(diào)用set方法比較多的(應(yīng)該都是這樣的吧)。
從代碼層面上,構(gòu)造器傳參的代碼是最簡短的,但在現(xiàn)實層面上我們很難每次都可以通過構(gòu)造器傳參的方式去完成對象的創(chuàng)建(更多的時候每個對象的屬性都是不一致的)。
構(gòu)造器的代碼看起來非常短,但閱讀起來不太友好(我得去看每個參數(shù)是什么意思);
而set方法寫起來不太方便,如果對象的屬性較多,也會有一大串的set代碼。
而文章最開始的builer鏈?zhǔn)?/strong>調(diào)用就很舒服,我一看這代碼就知道這肯定是哪種我不知道的設(shè)計模式。
于是我一查,原來這就叫做建造者模式。
怎么實現(xiàn)建造者模式?
建造者模式更多的是寫法上的不同,從代碼結(jié)構(gòu)層面上其實沒有很大的區(qū)別,只是看起來會更清爽一些。
那怎么實現(xiàn)建造者模式呢?其實也非常簡單:
- 在domain類上創(chuàng)建一個靜態(tài)內(nèi)部類 Builder,Builder擁有domain所有的屬性
- 在domain類上創(chuàng)建一個
private的構(gòu)造函數(shù),參數(shù)為Builder類型,里邊將Builder的屬性賦值給domain的屬性 - 在Builder內(nèi)部類創(chuàng)建domain屬性的賦值方法,返回值是Builder
- Builder內(nèi)部類創(chuàng)建一個
build方法,返回domain實例
下面我們來實現(xiàn)一下吧,首先創(chuàng)建一個靜態(tài)內(nèi)部類Builder,并且內(nèi)部類Builder擁有domain的所有屬性:
public?class?MessageTask?{
????private?String?taskId;
????private?String?content;
????private?String?messageId;
????private?String?taskName;
?
???//?創(chuàng)建內(nèi)部類
????public?static?class?Builder{
????????private?String?taskId;
????????private?String?content;
????????private?String?messageId;
????????private?String?taskName;
????}
}
在domain類上創(chuàng)建一個private的構(gòu)造函數(shù),參數(shù)為Builder類型,里邊是將Builder的屬性賦值給domain的屬性:
public?class?MessageTask?{
????private?String?taskId;
????private?String?content;
????private?String?messageId;
????private?String?taskName;
???//?增加private構(gòu)造函數(shù)
????private?MessageTask(Builder?builder)?{
????????this.taskId?=?builder.taskId;
????????this.content?=?builder.content;
????????this.messageId?=?builder.messageId;
????????this.taskName?=?builder.taskName;
????}
????public?static?class?Builder{
????????private?String?taskId;
????????private?String?content;
????????private?String?messageId;
????????private?String?taskName;
????}
}
在Builder內(nèi)部類創(chuàng)建domain屬性的賦值方法,返回值是Builder
public?class?MessageTask?{
????private?String?taskId;
????private?String?content;
????private?String?messageId;
????private?String?taskName;
????private?MessageTask(Builder?builder)?{
????????this.taskId?=?builder.taskId;
????????this.content?=?builder.content;
????????this.messageId?=?builder.messageId;
????????this.taskName?=?builder.taskName;
????}
????public?static?class?Builder{
????????private?String?taskId;
????????private?String?content;
????????private?String?messageId;
????????private?String?taskName;
????????//?賦值屬性的方法(返回的是Builder)
????????public?Builder?setTaskId(String?taskId)?{
????????????this.taskId?=?taskId;
????????????return?this;
????????}
????????public?Builder?setContent(String?content)?{
????????????this.content?=?content;
????????????return?this;
????????}
????????public?Builder?setMessageId(String?messageId)?{
????????????this.messageId?=?messageId;
????????????return?this;
????????}
????????public?Builder?setTaskName(String?taskName)?{
????????????this.taskName?=?taskName;
????????????return?this;
????????}
????}
}
在Builder內(nèi)部類創(chuàng)建一個builde方法,返回domain實例
public?class?MessageTask?{
????private?String?taskId;
????private?String?content;
????private?String?messageId;
????private?String?taskName;
????private?MessageTask(Builder?builder)?{
????????this.taskId?=?builder.taskId;
????????this.content?=?builder.content;
????????this.messageId?=?builder.messageId;
????????this.taskName?=?builder.taskName;
????}
????public?static?class?Builder{
????????private?String?taskId;
????????private?String?content;
????????private?String?messageId;
????????private?String?taskName;
??????
????????public?Builder?setTaskId(String?taskId)?{
????????????this.taskId?=?taskId;
????????????return?this;
????????}
????????public?Builder?setContent(String?content)?{
????????????this.content?=?content;
????????????return?this;
????????}
????????public?Builder?setMessageId(String?messageId)?{
????????????this.messageId?=?messageId;
????????????return?this;
????????}
????????public?Builder?setTaskName(String?taskName)?{
????????????this.taskName?=?taskName;
????????????return?this;
????????}
??????
????//?創(chuàng)建build方法,返回實例
????????public?MessageTask?build()?{
????????????return?new?MessageTask(this);
????????}
????}
}
使用方式:先創(chuàng)建Builder對象,然后用Builder去賦值,最后再調(diào)用build()返回真正的實例:
MessageTask.Builder?builder?=?new?MessageTask.Builder();
MessageTask?task?=?builder.setContent("關(guān)注?Java3y?吧?>>")
??.setTaskId("3y")
??.setTaskName("一起來玩")
??.setMessageId(String.valueOf(ThreadLocalRandom.current().nextLong()))
??.build();
借助工具使用建造者模式
從使用的角度感覺是好用了,代碼也清爽了。其實可以發(fā)現(xiàn)的是,我們都把邏輯寫到了Domain類上,這寫起來肯定是需要花時間的。
我第一印象是:這種這么通用的東西,肯定是有可以一鍵生成的方法的,于是我瞄準(zhǔn)了Lombok
果不其然,我們?nèi)绻褂昧?code style="font-size:14px;background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(40,202,113);">Lombok后,在類上加上一個注解@Builder就可以使用建造者模式的代碼了,非常方便
@Builder
@Data
public?class?MessageTask?{
????private?String?taskId;
????private?String?content;
????private?String?messageId;
????private?String?taskName;
}
又想了一下,IDEA這么強大,感覺IDEA也有辦法去生成Builder,也果不其然:

做個小調(diào)查:
- 如果你之前已經(jīng)了解過了建造者模式,你在項目中有用嗎?
- 如果你看了這篇文章才了解到了建造者模式,你在以后會用嗎?
我個人是看團(tuán)隊的代碼風(fēng)格的,如果原有已經(jīng)是各種set去構(gòu)造對象,那我就不會再修改了。如果是新寫的業(yè)務(wù),會使用建造者模式。
各類知識點總結(jié)
下面的文章都有對應(yīng)的原創(chuàng)精美PDF,在持續(xù)更新中,可以來找我催更~
- 92頁的Mybatis
- 129頁的多線程
- 141頁的Servlet
- 158頁的JSP
- 76頁的集合
- 64頁的JDBC
- 105頁的數(shù)據(jù)結(jié)構(gòu)和算法
- 142頁的Spring
- 58頁的過濾器和監(jiān)聽器
- 30頁的HTTP
- 42頁的SpringMVC
- Hibernate
- AJAX
- Redis
- ......
掃碼或者微信搜Java3y?免費領(lǐng)取原創(chuàng)思維導(dǎo)圖、精美PDF。在公眾號回復(fù)「888」領(lǐng)取,PDF內(nèi)容純手打有任何不懂歡迎來問我。
原創(chuàng)電子書
原創(chuàng)思維導(dǎo)圖

![]() |
|


