文章目录
1. 什么是建造者模式?
建造者模式是一种创建型设计模式,它允许你分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。
建造者模式的核心思想是将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
2. 为什么需要建造者模式?
在以下情况下,建造者模式特别有用:
- 当对象构造很复杂,有很多参数时
- 当对象的创建过程需要更多的控制
- 当需要创建不同表示的复杂对象
- 当构造函数参数过多造成的"重叠构造函数"问题
3. 建造者模式的结构
建造者模式通常包含以下几个角色:
- 产品(Product):最终要创建的复杂对象
- 抽象建造者(Builder):定义创建产品各个部件的抽象方法
- 具体建造者(ConcreteBuilder):实现抽象建造者的方法,完成产品的各个部件的创建
- 指挥者(Director):调用建造者的部件创建方法,以按照一定顺序完成产品的创建
4. 建造者模式的基本实现
基础示例:创建一个汽车对象
首先,我们定义产品类:
// 产品类
public class Car {
private String brand; // 品牌
private String model; // 型号
private String color; // 颜色
private int doors; // 车门数量
private String engine; // 引擎类型
private boolean hasGPS; // 是否有GPS
private boolean hasAirConditioner; // 是否有空调
// 查看汽车信息的方法
public void showInfo() {
System.out.println("汽车信息:");
System.out.println("品牌:" + brand);
System.out.println("型号:" + model);
System.out.println("颜色:" + color);
System.out.println("车门数:" + doors);
System.out.println("引擎:" + engine);
System.out.println("GPS:" + (hasGPS ? "有" : "无"));
System.out.println("空调:" + (hasAirConditioner ? "有" : "无"));
}
// Getter和Setter方法
public String getBrand() { return brand; }
public void setBrand(String brand) { this.brand = brand; }
public String getModel() { return model; }
public void setModel(String model) { this.model = model; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
public int getDoors() { return doors; }
public void setDoors(int doors) { this.doors = doors; }
public String getEngine() { return engine; }
public void setEngine(String engine) { this.engine = engine; }
public boolean isHasGPS() { return hasGPS; }
public void setHasGPS(boolean hasGPS) { this.hasGPS = hasGPS; }
public boolean isHasAirConditioner() { return hasAirConditioner; }
public void setHasAirConditioner(boolean hasAirConditioner) { this.hasAirConditioner = hasAirConditioner; }
}
然后,我们定义抽象建造者:
// 抽象建造者
public interface CarBuilder {
CarBuilder setBrand(String brand);
CarBuilder setModel(String model);
CarBuilder setColor(String color);
CarBuilder setDoors(int doors);
CarBuilder setEngine(String engine);
CarBuilder setGPS(boolean hasGPS);
CarBuilder setAirConditioner(boolean hasAirConditioner);
Car build(); // 构建并返回汽车
}
接着,我们实现具体建造者:
// 具体建造者
public class ConcreteCarBuilder implements CarBuilder {
private Car car;
public ConcreteCarBuilder() {
this.car = new Car();
}
@Override
public CarBuilder setBrand(String brand) {
car.setBrand(brand);
return this;
}
@Override
public CarBuilder setModel(String model) {
car.setModel(model);
return this;
}
@Override
public CarBuilder setColor(String color) {
car.setColor(color);
return this;
}
@Override
public CarBuilder setDoors(int doors) {
car.setDoors(doors);
return this;
}
@Override
public CarBuilder setEngine(String engine) {
car.setEngine(engine);
return this;
}
@Override
public CarBuilder setGPS(boolean hasGPS) {
car.setHasGPS(hasGPS);
return this;
}
@Override
public CarBuilder setAirConditioner(boolean hasAirConditioner) {
car.setHasAirConditioner(hasAirConditioner);
return this;
}
@Override
public Car build() {
return car;
}
}
然后,我们定义指挥者:
// 指挥者
public class CarDirector {
private CarBuilder builder;
public CarDirector(CarBuilder builder) {
this.builder = builder;
}
// 构建一个标准轿车
public Car constructSedanCar() {
return builder
.setBrand("大众")
.setModel("帕萨特")
.setColor("黑色")
.setDoors(4)
.setEngine("2.0T")
.setGPS(true)
.setAirConditioner(true)
.build();
}
// 构建一个运动型汽车
public Car constructSportsCar() {
return builder
.setBrand("保时捷")
.setModel("911")
.setColor("红色")
.setDoors(2)
.setEngine("3.0T")
.setGPS(true)
.setAirConditioner(true)
.build();
}
// 构建一个经济型汽车
public Car constructEconomyCar() {
return builder
.setBrand("丰田")
.setModel("卡罗拉")
.setColor("白色")
.setDoors(4)
.setEngine("1.6L")
.setGPS(false)
.setAirConditioner(true)
.build();
}
}
最后,我们来看看如何使用:
public class BuilderPatternDemo {
public static void main(String[] args) {
// 创建建造者
CarBuilder builder = new ConcreteCarBuilder();
// 创建指挥者并设置建造者
CarDirector director = new CarDirector(builder);
// 使用指挥者创建不同类型的汽车
System.out.println("===== 轿车 =====");
Car sedanCar = director.constructSedanCar();
sedanCar.showInfo();
System.out.println("\n===== 运动车 =====");
Car sportsCar = director.constructSportsCar();
sportsCar.showInfo();
System.out.println("\n===== 经济型车 =====");
Car economyCar = director.constructEconomyCar();
economyCar.showInfo();
// 不使用指挥者,直接使用建造者
System.out.println("\n===== 自定义汽车 =====");
Car customCar = new ConcreteCarBuilder()
.setBrand("特斯拉")
.setModel("Model 3")
.setColor("蓝色")
.setDoors(4)
.setEngine("电动")
.setGPS(true)
.setAirConditioner(true)
.build();
customCar.showInfo();
}
}
5. 建造者模式的简化版本
在Java中,我们经常会看到建造者模式的简化版本,尤其是当我们不需要指挥者角色时。这种模式常被称为"流式建造者模式"。
简化示例:创建一个用户对象
public class User {
// 必要参数
private final String firstName; // 名字
private final String lastName; // 姓氏
// 可选参数
private final int age; // 年龄
private final String phone; // 电话
private final String address; // 地址
private final String email; // 邮箱
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
this.email = builder.email;
}
// Getter方法
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
public String getEmail() {
return email;
}
@Override
public String toString() {
return "用户信息: " +
"姓名=" + firstName + " " + lastName +
", 年龄=" + age +
", 电话='" + phone + '\'' +
", 地址='" + address + '\'' +
", 邮箱='" + email + '\'';
}
// 静态内部建造者类
public static class UserBuilder {
// 必要参数
private final String firstName;
private final String lastName;
// 可选参数 - 初始化为默认值
private int age = 0;
private String phone = "";
private String address = "";
private String email = "";
// 构造函数设置必要参数
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// 为可选参数设置方法,并返回this以便链式调用
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public UserBuilder email(String email) {
this.email = email;
return this;
}
// 构建并返回用户对象
public User build() {
return new User(this);
}
}
}
使用示例:
public class UserBuilderDemo {
public static void main(String[] args) {
User user1 = new User.UserBuilder("张", "三")
.age(30)
.phone("13812345678")
.address("北京市海淀区")
.email("zhangsan@example.com")
.build();
System.out.println(user1);
User user2 = new User.UserBuilder("李", "四")
.age(25)
.phone("13987654321")
.build();
System.out.println(user2);
}
}
6. 建造者模式的实际应用场景
1. Java中的StringBuilder和StringBuffer
Java标准库中的StringBuilder
和StringBuffer
类就是建造者模式的经典应用:
// 使用StringBuilder构建字符串
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("你好,")
.append("世界!")
.append("这是一个")
.append("建造者模式的示例。");
String result = stringBuilder.toString();
System.out.println(result);
2. 使用Lombok简化建造者模式
在实际项目中,我们可以使用Lombok库提供的@Builder
注解来自动生成建造者模式的代码:
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class Person {
private String name;
private int age;
private String address;
private String email;
private String phone;
}
使用示例:
Person person = Person.builder()
.name("王五")
.age(28)
.address("上海市浦东新区")
.email("wangwu@example.com")
.phone("13600000000")
.build();
System.out.println(person);
3. Web请求构建
在HTTP客户端库中,常常使用建造者模式来构建请求:
// 使用OkHttp构建HTTP请求
Request request = new Request.Builder()
.url("https://api.example.com/data")
.header("Authorization", "Bearer token123456")
.get()
.build();
// 使用HttpClient构建请求
HttpGet httpGet = HttpGet.builder()
.uri(URI.create("https://api.example.com/data"))
.header("Accept", "application/json")
.build();
7. 建造者模式与其他设计模式的区别
建造者模式 vs 工厂模式
建造者模式 | 工厂模式 |
---|---|
关注于分步创建复杂对象 | 关注于根据参数创建不同类型的对象 |
提供对象的创建过程细节控制 | 隐藏对象的创建过程 |
适用于构建复杂对象 | 适用于创建类型相似的对象 |
建造者模式 vs 抽象工厂模式
建造者模式 | 抽象工厂模式 |
---|---|
一步一步构建单个复杂对象 | 创建一系列相关或相互依赖的对象家族 |
强调对象构建过程 | 强调对象间的关系 |
8. 建造者模式的优缺点
优点
- 分离了对象的创建和表示
- 相同的创建过程可以产生不同的表示
- 可以更精细地控制创建过程
- 代码可读性好,链式调用使代码更直观
- 避免了"重叠构造函数"的问题
缺点
- 代码量增加,需要创建额外的建造者类
- 对于参数较少的简单对象,使用建造者模式可能会过度设计
9. 什么时候应该使用建造者模式?
- 当对象有非常多的属性和参数时
- 当需要创建不可变对象时
- 当对象的构建过程比较复杂时
- 当对象的构建需要按照特定顺序进行时
- 当你希望使用相同的创建代码来获取不同的表示时
10. 常见问题及解决方案
问题1:如何处理必要参数和可选参数?
解决方案:在建造者的构造函数中设置必要参数,而可选参数通过方法设置。
问题2:如何确保对象的一致性?
解决方案:可以在build()
方法中添加验证逻辑,确保创建的对象符合要求。
public User build() {
// 添加验证逻辑
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
if (email != null && !email.contains("@")) {
throw new IllegalArgumentException("邮箱格式不正确");
}
return new User(this);
}
问题3:如何处理继承关系中的建造者模式?
解决方案:使用泛型和递归类型参数:
public abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
protected String property;
public T setProperty(String property) {
this.property = property;
return self();
}
protected abstract T self();
public abstract Product build();
}
public class ConcreteBuilder extends AbstractBuilder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
@Override
public Product build() {
return new Product(property);
}
}
总结
建造者模式是一种强大的创建型设计模式,特别适合于构建复杂对象。它将对象的构建过程与表示分离,使得同样的构建过程可以创建不同的表示。在Java中,建造者模式特别有用,可以避免"重叠构造函数"问题,提高代码的可读性和维护性。