透過lombok帶你讀透Builder構建器
透過lombok帶你讀透Builder構建器
很久之前,我在《effective java》上看過Builder構建器相關的內容,但實際開發中不經常用。後來,在專案中使用了lombok,發現它有一個註解“@Builder”,就是為java bean生成一個構建器。於是,回頭重新複習了下相關知識,整理如下。
lombok使用樣例
// 建立名為Officer的java bean@Builderpublic class Officer { private final String id; private final String name; private final int age; private final String department; }// 呼叫構建器生成Officer例項class BuilderTest { public static void main(String[] args) { Officer officer = Officer.builder().id("00001").name("simon qi") .age(26).department("departmentA").build(); } }
反編譯lombok生成的Officer.class
注意:下面請區分兩組名詞:"builder方法"和“build方法”,“構造器”和“構建器”。
public class Officer { private final String id; private final String name; private final int age; private final String department; Officer(String id, String name, int age, String department) { this.id = id; this.name = name; this.age = age; this.department = department; } public static Officer.OfficerBuilder builder() { return new Officer.OfficerBuilder(); } public static class OfficerBuilder { private String id; private String name; private int age; private String department; OfficerBuilder() { } public Officer.OfficerBuilder id(String id) { this.id = id; return this; } public Officer.OfficerBuilder name(String name) { this.name = name; return this; } public Officer.OfficerBuilder age(int age) { this.age = age; return this; } public Officer.OfficerBuilder department(String department) { this.department = department; return this; } public Officer build() { return new Officer(this.id, this.name, this.age, this.department); } public String toString() { return "Officer.OfficerBuilder(id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", department=" + this.department + ")"; } } }
我們透過反編譯Officer.class,獲得上方的原始碼(最好用idea自帶的反編譯器,jd-gui反編譯的原始碼不全)。
我們發現原始碼中有一個OfficerBuilder的靜態內部類,我們在呼叫builder方法時,實際返回了這個靜態內部類的例項。這個OfficerBuilder類,具有和Officer相同的成員變數,且擁有名為id,name,age和department的方法。這些以Officer的成員變數命名的方法,都是給OfficerBuilder的成員變數賦值,並返回this。
這些方法返回this,其實就是返回撥用這些方法的OfficerBuilder物件,也可稱為“返回物件本身”。透過返回物件本身,形成了方法的鏈式呼叫。
再看build方法,它是OfficerBuilder類的方法。它建立了一個新的Officer物件,並將自身的成員變數值,傳給了Officer的成員變數。所以“Officer officer = Officer.builder().id("00001").name("simon qi").age(26).department("departmentA").build();”的寫法,等價於下面的寫法:
Officer.OfficerBuilder officerBuilder = new Officer.OfficerBuilder(); officerBuilder.id("00001").name("simon qi").age(26).department("departmentA"); Officer officer = officerBuilder.build(); System.out.println(officer);
所以為什麼這種模式叫“構建器”,因為要建立Officer類的例項,首先要建立OfficerBuilder類的例項。而這個OfficerBuilder也就是構建器,是建立Officer物件的一個過渡者。所以利用這種模式,會有中間例項的建立,會加大虛擬機器記憶體的消耗。
只用@Builder註解的bug
我們只用@Builder註解,我發現lombok為Officer類生成的構造器是“default”的(不新增許可權修飾符,預設為“default”的)。我們之所以用構建器模式,是希望使用者用構建器提供的方法去建立例項。但“default”的構造器,可以被同package的類呼叫(default限制不同package類的呼叫)。所以,我們需要將此構造器設為private的。這時就需要用到“@AllArgsConstructor(access = AccessLevel.PRIVATE)”。我們這時再看反編譯後的構造器:
private Officer(String id, String name, int age, String department) { this.id = id; this.name = name; this.age = age; this.department = department; }
所以,使用lombok的構建器,應將“@Builder”和“@AllArgsConstructor(access = AccessLevel.PRIVATE)”相結合,最終寫法:
@Builder@AllArgsConstructor(access = AccessLevel.PRIVATE)public class Officer { private final String id; private final String name; private final int age; private final String department; }
為什麼使用構建器模式
若一個類具有大量的成員變數,我們就需要提供一個全參的構造器或大量的set方法。這讓例項的建立和賦值,變得很麻煩,且不直觀。我們透過構建器,可以讓變數的賦值變成鏈式呼叫,而且呼叫的方法名對應著成員變數的名稱。讓物件的建立和賦值都變得很簡潔、直觀。
鏈式方法賦值,一定要用構建器模式嗎?
不一定要用到構建器模式,之所以使用構建器模式,是因為我們要創造的物件是一個成員變數不可變的物件。
你返回去看Officer類和OfficerBuilder類,你會發現Officer類的成員變數都是final的,而OfficerBuilder的成員變數卻沒用final修飾。因為final修飾的成員變數,需要在例項建立時就把值確定下來。但在類具有大量成員變數的時候,我們是不希望使用者直接呼叫全參構造器的。所以我們使用了OfficerBuilder的中間類。這個類為了實現鏈式賦值,才將變數設為非final的。無論你OfficerBuilder例項怎麼賦值,怎麼改變,但你呼叫build方法時,就會返回一個成員變數不可變的Officer例項。
那如果有大量屬性,但不需要它是成員變數不可變的物件,我們還需要構建器模式嗎?答案是,不需要,我們可以參考構建器,把程式碼賦值改成鏈式的即可:
public class Officer { private String id; private String name; private int age; private String department; public static Officer build() { return new Officer(); } private Officer() { } public Officer id(String id) { this.id = id; return this; } public Officer name(String name) { this.name = name; return this; } public Officer age(int age) { this.age = age; return this; } public Officer department(String department) { this.department = department; return this; } } 呼叫樣式: Officer officer = Officer.build().id("00001").name("simon qi").age(26).department("departmentA"); 其實這時候構造器設為非private也行,寫成private,只是為了呼叫build()顯得更好看。 將構造器設為非private,可以寫為如下形式: Officer officer = new Officer().id("00001").name("simon qi").age(26).department("departmentA");
所以,我覺得你在使用lombok的"@Builder"註解的時候,還是要思考一下。當你不需要成員變數不可變的時候,你完全沒必要使用構建器模式,因為這會消耗java虛擬機器的記憶體。
總結
所以,我一直推薦學習知識,要在專案中去學習。透過專案,去探索專案以外的知識點,才是提升自己的快捷方法。而且知識不能學死了,不能網上有哪些知識點,我們就只考慮這些知識點。我們要去思考一些別人不常想到的問題。比如,我們為什麼要用中間類去做過渡,這麼寫的目的是什麼。
將上述知識吃透,面試應對構建器的時候,也就得心應手了。而且透過實戰去回答問題,也更能彰顯你是個愛思考的員工。
作者:simonQi
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/964/viewspace-2815848/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 透過結構化資料構建頁面
- Java構建器(Builder)JavaUI
- 如何透過建構函式和JPQL生成DTO?函式
- 透過6個示例帶你掌握Linux sed命令!Linux
- 透過chroot構建Linux作業系統(轉)Linux作業系統
- 透過8個小例子帶你掌握Linux Head命令!Linux
- 九大步驟帶你瞭解如何透過路由器保護內網安全!路由器內網
- 一文帶你理解透MyBatis原始碼MyBatis原始碼
- 帶貨直播系統,透過主從同步實現讀寫分離主從同步
- 透過重構來加深理解——DDD
- 透過oracle的指令碼研究其建庫過程Oracle指令碼
- 遠端控制篇:透過機器名得到IP地址 透過IP地址得到機器名 (轉)
- 透過閱讀本篇文章你將瞭解到:CompletableFuture的使用
- 透過python讀取ini配置檔案Python
- 直接透過DAO讀、寫Access檔案 (轉)
- QtCreator透過CMake構建專案,修改專案名稱後報錯。QT
- 透過機器人應用視覺機器人視覺
- 透過瀏覽器看HTTP快取瀏覽器HTTP快取
- 見微知著 帶你透過記憶體看 Slice 和 Array的異同記憶體
- 大手筆!谷歌透過Knative壓賭無伺服器架構谷歌伺服器架構
- 帶你學習透過GitHub Actions如何快速構建和部署你自己的專案,打造一條屬於自己的流水線Github
- 透過阿里雲“人臉口罩檢測”能力構建疫情防控能力阿里
- 談談如何透過構建資料產品釋放資料價值
- Builder設計模式結合lombok減少過多傳參UI設計模式Lombok
- OpenHarmony自定義構建函式:@Builder裝飾器函式UI
- 構建者模式(Builder pattern)模式UI
- 透過Github同步你的VScode設定GithubVSCode
- 透過Ubuntu虛擬機器+Linux移植LVGL並透過linux Frame buffer顯示Ubuntu虛擬機Linux
- Oracle 透過透明閘道器 訪問 mysqlOracleMySql
- 透過NandGame網站學習選擇器NaNGAM網站
- 我試圖透過這篇文章,教會你一種閱讀原始碼的方式。原始碼
- 一篇漫畫故事帶你理解透HTTPS(下)HTTP
- “大資料”帶你透視考研當下與未來大資料
- 透過構建具有依賴關係的後端框架來學習 Nodejs後端框架NodeJS
- 透過遊戲學習計算機架構 - embeddedartistry遊戲計算機架構Dart
- 透過訪問URL地址,5分鐘內滲透你的網站!很刑很可拷!網站
- 透過 Chrome 深入理解瀏覽器導航過程Chrome瀏覽器
- 華為構建鯤鵬生態 東軟資料中臺透過相容性認證