做網(wǎng)站的書籍推薦網(wǎng)絡(luò)小說網(wǎng)站三巨頭
楔子
小七在2019年的時候,就想寫一個關(guān)于設(shè)計模式的專欄,但是最終卻半途而廢了。粗略一想,如果做完一件事要100分鐘,小七用3分鐘熱情做的事,最少也能完成10件事情了。所以這一次,一定要把他做完,fighting!
需求背景
以以前小七做的一個政務(wù)系統(tǒng)為例,為了符合國標(biāo),數(shù)據(jù)庫表需要設(shè)計很多字段,大概有100多個。每次new這個實(shí)體的時候,都會調(diào)用大量的set方法,關(guān)鍵是這100個字段基本不會變,但是他們的組合卻經(jīng)常變,弄得開發(fā)的小伙伴們苦不堪言,于是前輩們就重載了很多的構(gòu)造方法,結(jié)果構(gòu)造方法也爆炸了,導(dǎo)致新來的后浪們差點(diǎn)直接被拍死在了沙灘上。
為了簡化代碼,咱們這一次就定義一個Student類,里面只包含name和age。
分析設(shè)計
因?yàn)檫@個對象的屬性很多,且組合方式很自由,如果使用經(jīng)典的new-set方式,代碼大概如下:
BigObject bigObject = new BigObject();
bigObject.setO1("");
bigObject.setO2("");
bigObject.setO3("");
bigObject.setO4("");
bigObject.setO5("");
bigObject.setO6("");
bigObject.setO7("");
bigObject.setO8("");
bigObject.setO9("");
bigObject.setO10("");
...
bigObject.setO100("");
看起來并不直觀。
如果每一個組合就重載一個構(gòu)造方法,也會產(chǎn)生很多構(gòu)造方法,并且語義不明,新來的小伙伴會一臉懵逼。
但是如果我們能夠抽象一下產(chǎn)品的構(gòu)建過程,具體建造者類繼承自抽象建造者類,實(shí)現(xiàn)具體的構(gòu)建邏輯。指揮者類負(fù)責(zé)調(diào)用具體建造者類的構(gòu)建方法,完成產(chǎn)品的構(gòu)建。這樣就可以降低客戶端代碼的復(fù)雜度,提高代碼的可維護(hù)性。
定義 | 類名 |
---|---|
產(chǎn)品類 | Student |
抽象建造者類 | StudentBuilder |
具體建造者類 | StudentActualBuilder |
指揮者類 | Commander |
標(biāo)準(zhǔn)建造者模式
UML圖
根據(jù)分析設(shè)計,我們可以先畫一個簡單的UML圖,后面通過UML圖編碼
模塊名稱
builder.demo01
模塊地址
https://gitee.com/diqirenge/design-pattern/tree/master/src/main/java/com/run2code/design/creational/builder/demo01
模塊描述
經(jīng)典模式代碼示例
代碼實(shí)現(xiàn)
1、定義產(chǎn)品類
/*** 定義產(chǎn)品類* 關(guān)注公眾號【奔跑的碼畜】,一起進(jìn)步不迷路** @author 第七人格* @date 2023/11/20*/
public class Student {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
2、定義抽象建造者類
/*** 定義抽象建造者類* 關(guān)注公眾號【奔跑的碼畜】,一起進(jìn)步不迷路** @author 第七人格* @date 2023/11/20*/
public abstract class StudentBuilder {public abstract void buildName(String name);public abstract void buildAge(int age);public abstract Student makeStudent();
}
3、定義具體建造者類
/*** 定義具體建造者類* 關(guān)注公眾號【奔跑的碼畜】,一起進(jìn)步不迷路** @author 第七人格* @date 2023/11/20*/
public class StudentActualBuilder extends StudentBuilder {/*** 這里使用組合,將 student 組合到實(shí)現(xiàn)類中*/private Student student = new Student();@Overridepublic void buildName(String name) {student.setName(name);}@Overridepublic void buildAge(int age) {student.setAge(age);}@Overridepublic Student makeStudent() {return student;}
}
4、定義指揮者類
/*** 定義指揮者類* 關(guān)注公眾號【奔跑的碼畜】,一起進(jìn)步不迷路** @author 第七人格* @date 2023/11/20*/
public class Commander {/*** 注入StudentBuilder*/private StudentBuilder studentBuilder;public void setStudentBuilder(StudentBuilder studentBuilder) {this.studentBuilder = studentBuilder;}public Student makeStudent(String name, int age) {this.studentBuilder.buildAge(age);this.studentBuilder.buildName(name);return this.studentBuilder.makeStudent();}
}
5、測試
public class BuilderStudentBuilderTest {@Testpublic void testBuild_01() {System.out.println("==========標(biāo)準(zhǔn)建造者模式開始==========");StudentActualBuilder studentActualBuilder = new StudentActualBuilder();Commander commander = new Commander();commander.setStudentBuilder(studentActualBuilder);// 客戶端使用指揮者類創(chuàng)建產(chǎn)品對象,這樣可以降低客戶端代碼的復(fù)雜度,提高代碼的可維護(hù)性。Student student = commander.makeStudent("第七人格", 18);System.out.println(student);System.out.println("==========標(biāo)準(zhǔn)建造者模式結(jié)束==========");}
}
6、測試結(jié)果
==========標(biāo)準(zhǔn)建造者模式開始==========
Student{name='第七人格', age=18}
==========標(biāo)準(zhǔn)建造者模式結(jié)束==========
實(shí)現(xiàn)要點(diǎn)
定義產(chǎn)品類:產(chǎn)品類是最終要構(gòu)建的對象,包含多個屬性和方法。
定義抽象建造者類:抽象建造者類定義了產(chǎn)品的構(gòu)建過程,包括各個部分的構(gòu)建方法和返回最終產(chǎn)品的方法。
定義具體建造者類:具體建造者類繼承自抽象建造者類,實(shí)現(xiàn)具體的構(gòu)建邏輯。
定義指揮者類:指揮者類負(fù)責(zé)調(diào)用具體建造者類的構(gòu)建方法,完成產(chǎn)品的構(gòu)建。
用過StringBuilder的我們知道,StringBuilder有個append方法,我們學(xué)著StringBuilder將上面的代碼,改為鏈?zhǔn)秸{(diào)用。
鏈?zhǔn)秸{(diào)用模式
URL圖
模塊名稱
builder.demo02
模塊地址
https://gitee.com/diqirenge/design-pattern/tree/master/src/main/java/com/run2code/design/creational/builder/demo02
模塊描述
建造者-鏈?zhǔn)秸{(diào)用
代碼實(shí)現(xiàn)
/*** 鏈?zhǔn)秸{(diào)用建造者示例* 關(guān)注公眾號【奔跑的碼畜】,一起進(jìn)步不迷路** @author 第七人格* @date 2023/11/20*/
public class Student02Builder {/*** 姓名*/private String name;/*** 年齡*/private int age;/*** 學(xué)生類的構(gòu)造函數(shù)** @param name 的名字* @param age 年齡*/Student02Builder(String name, int age) {this.name = name;this.age = age;}/*** 構(gòu)建器(本質(zhì)上就是指揮者Commander)** @return {@link StudentBuilder}*/public static Student02Builder.StudentBuilder builder() {// 構(gòu)造一個StudentBuilder對象return new Student02Builder.StudentBuilder();}/*** 學(xué)生構(gòu)建器(相當(dāng)于StudentBuilder及其實(shí)現(xiàn)類StudentActualBuilder)** @author 第七人格* @date 2020/12/02*/public static class StudentBuilder {private String name;private int age;public StudentBuilder() {}public Student02Builder.StudentBuilder name(String name) {this.name = name;// 返回自身(StudentBuilder),以便鏈?zhǔn)秸{(diào)用return this;}public Student02Builder.StudentBuilder age(int age) {this.age = age;// 返回自身(StudentBuilder),以便鏈?zhǔn)秸{(diào)用return this;}/*** 構(gòu)建** @return {@link Student02Builder}*/public Student02Builder build() {// 構(gòu)造一個Student對象,其中的屬性直接從外部傳入return new Student02Builder(this.name, this.age);}@Overridepublic String toString() {return "Student.StudentBuilder(name=" + this.name + ", age=" + this.age + ")";}}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
測試
@Test
public void testBuild_02() {System.out.println("==========工作中常用-建造者模式開始==========");System.out.println(Student02Builder.builder().age(18).name("第七人格").build());System.out.println("==========工作中常用-建造者模式開始==========");
}
測試結(jié)果
==========鏈?zhǔn)秸{(diào)用-建造者模式開始==========
Student{name='第七人格', age=18}
==========鏈?zhǔn)秸{(diào)用-建造者模式開始==========
實(shí)現(xiàn)要點(diǎn)
1、使用靜態(tài)方法替換指揮者Commander
public static Student02Builder.StudentBuilder builder() {// 構(gòu)造一個StudentBuilder對象return new Student02Builder.StudentBuilder();
}
2、使用內(nèi)部類替換StudentBuilder及StudentActualBuilder
3、內(nèi)部類中設(shè)置屬性的時候,返回自身,以便鏈?zhǔn)秸{(diào)用
面對對象面對君,不負(fù)代碼不負(fù)卿