建造者模式
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 67 课,共 87 课。
构建器模式是一种创建型设计模式,用于解决一个常见问题:如何构造包含许多可选参数的复杂对象。你无需创建多个构造函数,也无需为未使用的参数传入 null,而是可以通过 Builder 一步步构造对象。
考虑创建一个包含必需字段(姓名、电子邮件)和可选字段(年龄、电话、地址)的 User 对象。如果不使用 Builder,你就需要使用层叠构造函数,或者编写一个包含许多参数的混乱构造函数。Builder 模式提供了一种更简洁的方法:
public class User {
private final String name; // 必填
private final String email; // 必填
private final int age; // 可选
private final String phone; // 可选
private User(UserBuilder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
}
public static class UserBuilder {
private final String name;
private final String email;
private int age;
private String phone;
public UserBuilder(String name, String email) {
this.name = name;
this.email = email;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
}Builder 的方法会返回 this,从而支持方法链式调用:这是一种流畅、易读的对象构造方式。
User user = new User.UserBuilder("Alice", "alice@email.com")
.age(25)
.phone("555-1234")
.build();注意,User 构造函数是私有的:只能通过 Builder 创建对象。当对象有许多可选字段时,这种模式特别有用,能让代码比使用很长的参数列表更易读,也更不容易出错。
挑战
简单让我们使用 Builder Pattern 构建一个披萨订购系统!你不必使用一个包含几十个参数、用于设置所有可能配料和选项的构造函数,而是创建一个流畅的构建器,让披萨定制变得清晰易读。
你需要将代码分成两个文件:
Pizza.java:创建一个使用 Builder Pattern 构造对象的Pizza类。披萨应包含以下字段:size(String):必需,表示披萨尺寸cheese(boolean):可选,默认值为 falsepepperoni(boolean):可选,默认值为 falsemushrooms(boolean):可选,默认值为 falsePizza构造函数应设为 private,并且只接受PizzaBuilder作为参数,将构建器中的所有值复制到披萨的字段中。添加一个
getDescription()方法,返回以下格式的字符串:[size] Pizza with: [toppings],其中 toppings 是一个逗号分隔的列表,列出值为 true 的配料(Cheese、Pepperoni、Mushrooms)。如果没有选择配料,配料部分应显示为no toppings。创建一个静态内部类
PizzaBuilder,其中包含:- 一个接受必需的
size参数的构造函数 cheese()、pepperoni()和mushrooms()方法,每个方法都会将对应的布尔值设为 true,并返回this,以便链式调用- 一个返回新建
Pizza的build()方法
- 一个接受必需的
Main.java:演示如何使用披萨构建器!你会收到 4 个输入:披萨尺寸(String),以及 3 个 yes/no 值(String),分别表示是否添加奶酪、意大利辣香肠和蘑菇。使用给定的尺寸创建一个
PizzaBuilder。然后,根据每个 yes/no 输入,链式调用对应的配料方法。如果输入是"yes",就调用对应的配料方法;如果是"no",则跳过该方法。最后,调用build()创建披萨。打印对创建完成的披萨调用
getDescription()后得到的结果。
你会依次收到 4 个输入:尺寸(String)、是否添加奶酪(String:"yes" 或 "no")、是否添加意大利辣香肠(String:"yes" 或 "no")、是否添加蘑菇(String:"yes" 或 "no")。
例如,输入为 Large、yes、no、yes 时,输出应为:Large Pizza with: Cheese, Mushrooms
注意,Builder Pattern 让你可以构建配料任意组合的披萨,而不需要为每种可能的组合单独创建构造函数!
亲手试试
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入
String size = scanner.nextLine();
String addCheese = scanner.nextLine();
String addPepperoni = scanner.nextLine();
String addMushrooms = scanner.nextLine();
// TODO:用给定的尺寸创建 PizzaBuilder
// TODO:根据 yes/no 输入,链式调用添加配料的方法
// TODO:构建披萨并打印其描述
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器