前言
在面向对象的软件开发中,构建复杂对象时经常会遇到许多挑战。一种常见的解决方案是使用设计模式,其中建造者模式是一个强大而灵活的选择。本文将深入探讨建造者模式的原理、结构、优点以及如何在实际项目中应用它。
一、复杂的对象
public class Computer {
private String ram;
private String hardDisk;
private String cpu;
// ...可能还有更多参数...
public Computer(String ram, String hardDisk, String cpu) {
this.ram = ram;
this.hardDisk = hardDisk;
this.cpu = cpu;
// ...初始化更多参数...
}
// getters and setters...
}
// 使用构造函数创建对象,参数多且容易混淆
Computer computer = new Computer("16GB", "1TB", "Intel i7");
上面代码比较简单,但是如果 Computer 类有更多的参数,构造函数将会变得非常长,而且在创建 Computer 对象时,传递参数的顺序非常重要,一旦顺序错误,就会创建出一个配置错误的对象。此外,如果参数有默认值,那么用户还需要记住哪些参数是必须的,哪些是可选的,这增加了使用的复杂性。
我们可以总结出创建复杂对象时可能会遇到的问题包括:
- 参数过多:构造函数或者 setter 方法的参数可能会非常多,导致代码难以阅读和维护。
- 参数顺序:容易混淆参数的顺序,特别是当有多个相同类型的参数时。
- 不够灵活:如果创建过程中需要多个步骤,使用构造函数或 setter 方法就不够灵活。
- 不可读性:代码的可读性差,特别是在没有注释的情况下,很难理解每个参数的意义。
二、建造者模式
建造者模式是一种创建型
设计模式,旨在将复杂对象的构建过程与其表示分离。通过使用建造者模式,可以使客户端代码与对象的内部结构解耦,从而使构建过程更加灵活,并且更易于维护和扩展。
三、建造者模式的核心组成部分
建造者模式通常包括以下几个关键组件:
- 产品(Product):表示被构建的复杂对象。产品类通常包含多个属性,并且可能包含一些复杂的业务逻辑。
- 抽象建造者(Builder):定义了构建产品所需的接口。抽象建造者通常包括一系列方法来构建产品的各个部分。
- 具体建造者(Concrete Builder):实现了抽象建造者接口,负责实际构建产品的各个部分,并提供方法来获取最终的产品实例。
- 指挥者(Director):负责调用建造者的方法来构建产品,但不直接创建产品的实例。指挥者通常根据一定的构建步骤来组织构建过程。
四、运用建造者模式
场景假设:我们要构建一台计算机,它有不同的部件,比如 CPU、内存、硬盘等。我们将使用建造者模式来构建这台计算机。
-
定义产品类: 首先,确定需要构建的复杂对象的属性和方法,并创建相应的产品类。这个产品类应该包含对象的所有属性,并提供相应的 getter 和 setter 方法。
/** * 产品类:计算机 */ public class Computer { private String cpu; // CPU private String memory; // 内存 private String hardDisk; // 硬盘 // 省略构造函数和 getter/setter方法 }
-
创建抽象建造者接口: 定义一个抽象建造者接口,该接口包含构建产品各个部件的抽象方法。这些方法代表构建产品所需的不同步骤。
/** * 抽象建造者接口 */ public interface ComputerBuilder { // 构建CPU void buildCPU(); // 构建内存 void buildMemory(); // 构建硬盘 void buildHardDisk(); // 构建计算机 Computer build(); }
-
实现具体建造者类: 创建一个或多个具体建造者类,实现抽象建造者接口。每个具体建造者类负责实现构建产品各个部件的具体方法,并在最后返回构建好的产品。
/** * 具体建造者类:桌面计算机建造者 */ public class DesktopComputerBuilder implements ComputerBuilder { private Computer computer; // 待构建的计算机对象 public DesktopComputerBuilder() { this.computer = new Computer(); } @Override public void buildCPU() { computer.setCpu("Intel Core i7"); } @Override public void buildMemory() { computer.setMemory("16GB DDR4"); } @Override public void buildHardDisk() { computer.setHardDisk("1TB SSD"); } @Override public Computer build() { // 返回构建好的计算机对象 return computer; } }
-
创建指挥者类: 定义一个指挥者类,该类负责使用具体建造者对象构建最终的产品。指挥者类知道构建者的具体实现细节,但与产品的实际构建过程无关。
/** * 指挥者类:计算机指挥者 */ public class ComputerDirector { private ComputerBuilder computerBuilder; // 建造者对象 public ComputerDirector(ComputerBuilder computerBuilder) { this.computerBuilder = computerBuilder; } // 使用建造者构建计算机对象 public Computer construct() { // 按照顺序调用建造者的方法来构建计算机 computerBuilder.buildCPU(); computerBuilder.buildMemory(); computerBuilder.buildHardDisk(); // 返回构建好的计算机对象 return computerBuilder.build(); } }
-
使用建造者模式构建对象: 在客户端代码中,创建具体的建造者对象,并将其传递给指挥者类。然后,通过指挥者类调用相应的方法来构建产品。最终,客户端代码可以获取构建好的产品并使用它。
public class Main { public static void main(String[] args) { // 创建桌面计算机的建造者对象 ComputerBuilder desktopBuilder = new DesktopComputerBuilder(); // 创建计算机指挥者对象,并传入桌面计算机的建造者 ComputerDirector director = new ComputerDirector(desktopBuilder); // 使用指挥者构建计算机对象 Computer desktop = director.construct(); // 输出构建好的桌面计算机的配置信息 System.out.println("Desktop Computer Configuration:"); System.out.println(desktop); } } /* 在一些简单的情况下,可以省略指挥者(Director)类。 特别是当只有一个具体建造者(Concrete Builder)时, 客户端代码可以直接调用具体建造者的方法来构建产品,而不需要指挥者类。 */ public class Main { public static void main(String[] args) { // 创建桌面计算机的建造者对象 ComputerBuilder desktopBuilder = new DesktopComputerBuilder(); // 使用桌面计算机的建造者直接构建计算机对象 Computer desktop = desktopBuilder.buildCPU() .buildMemory() .buildHardDisk() .build(); // 输出构建好的桌面计算机的配置信息 System.out.println("Desktop Computer Configuration:"); System.out.println(desktop); } }
在上面的例子中,我们定义了 Computer 类作为产品,ComputerBuilder 作为具体建造者来创建产品
,ComputerDirector 作为指导者确定创建产品时遵循的步骤流程
。客户端代码只需通过 ComputerDirector 便能构建 Computer 对象,这样就隐藏了构建细节,使得客户端代码更加简洁和易于维护。
五、建造者模式的应用场景
建造者模式适用于以下几种场景:
-
复杂对象的创建:当创建的对象非常复杂,包含多个组成部分时,建造者模式可以帮助管理复杂性,使得代码更加清晰。
// 假设我们需要创建一个复杂的 Pizza 对象,它包含多种配料和选项。 // 产品类 public class Pizza { private String dough; private String sauce; private String topping; // 私有构造器 private Pizza(Builder builder) { this.dough = builder.dough; this.sauce = builder.sauce; this.topping = builder.topping; } // Builder类 public static class Builder { private String dough; private String sauce; private String topping; public Builder withDough(String dough) { this.dough = dough; return this; } public Builder withSauce(String sauce) { this.sauce = sauce; return this; } public Builder withTopping(String topping) { this.topping = topping; return this; } public Pizza build() { return new Pizza(this); } } } // 客户端代码 // 在创建 Pizza 时,可以根据需要选择是否设置 dough、sauce、topping Pizza pizza = new Pizza.Builder() .withDough("cross") .withSauce("mild") .withTopping("ham and pineapple") .build();
-
构造过程需要分步骤进行:如果一个对象的构造过程需要分多个步骤或者阶段来完成,建造者模式允许你逐步构造对象,而不是一次性通过一个巨大的构造函数完成。
// 倘若 House 对象的构建,需要分步骤设置地基、结构、屋顶和内部装修。 // 产品类 public class House { private String foundation; private String structure; private String roof; private String interior; private House(Builder builder) { this.foundation = builder.foundation; this.structure = builder.structure; this.roof = builder.roof; this.interior = builder.interior; } // Builder类 public static class Builder { private String foundation; private String structure; private String roof; private String interior; public Builder withFoundation(String foundation) { this.foundation = foundation; return this; } public Builder withStructure(String structure) { this.structure = structure; return this; } public Builder withRoof(String roof) { this.roof = roof; return this; } public Builder withInterior(String interior) { this.interior = interior; return this; } public House build() { return new House(this); } } } // 客户端代码 // 在创建对象之前,可严格管控步骤的先后顺序 House house = new House.Builder() .withFoundation("concrete") .withStructure("wooden") .withRoof("shingle") .withInterior("painted") .build();
-
同一构建过程不同表示:当需要根据不同的需求和过程来创建不同的对象表示时,建造者模式提供了很好的解决方案。
// 如果我们有一个 Car 对象,它可以有不同的配置,例如经济型和豪华型。 // 产品类 public class Car { private String engine; private String seats; private String navigationSystem; private Car(Builder builder) { this.engine = builder.engine; this.seats = builder.seats; this.navigationSystem = builder.navigationSystem; } // Builder类 public static class Builder { private String engine; private String seats; private String navigationSystem; public Builder withEngine(String engine) { this.engine = engine; return this; } public Builder withSeats(String seats) { this.seats = seats; return this; } public Builder withNavigationSystem(String navigationSystem) { this.navigationSystem = navigationSystem; return this; } public Car build() { return new Car(this); } } } // 客户端代码 // 根据不同配置,满足不同需求 Car economyCar = new Car.Builder() .withEngine("1.5L") .withSeats("cloth") .build(); Car luxuryCar = new Car.Builder() .withEngine("3.0L V6") .withSeats("leather") .withNavigationSystem("advanced") .build();
-
参数多且复杂:当构造函数的参数非常多,且有些可能是可选的,建造者模式可以帮助组织这些参数,使得构造函数不会过于庞大和复杂。
// 倘若 Order 对象可能包含多个可选的配置项,如礼品包装、快递服务、优惠券等, // 使用建造者模式可以让客户端代码清晰地指定所需的配置。 // 产品类:具有多个配置参数,其中一些是可选的。 public class Order { private String product; private boolean giftWrap; private boolean expressDelivery; private String couponCode; // 私有构造器,只能通过Builder类构建Order对象 private Order(Builder builder) { this.product = builder.product; this.giftWrap = builder.giftWrap; this.expressDelivery = builder.expressDelivery; this.couponCode = builder.couponCode; } // Builder 类:提供了一个链式 API 来设置 Order 对象的属性 public static class Builder { private String product; private boolean giftWrap; private boolean expressDelivery; private String couponCode; public Builder(String product) { this.product = product; } public Builder setGiftWrap(boolean giftWrap) { this.giftWrap = giftWrap; return this; } public Builder setExpressDelivery(boolean expressDelivery) { this.expressDelivery = expressDelivery; return this; } public Builder setCouponCode(String couponCode) { this.couponCode = couponCode; return this; } // 构建方法:创建一个Order对象并返回 public Order build() { return new Order(this); } } } // 客户端使用:创建一个 Order 对象 Order order = new Order.Builder("Product1") .setGiftWrap(true) .setExpressDelivery(true) .setCouponCode("DISCOUNT10") .build();
六、小结
建造者模式是一种创建复杂对象的有效方式,它允许我们按照步骤构建对象,从而使得构建过程更加灵活和可配置。例如,在 Java 中,StringBuilder
是建造者模式的一个典型应用,它允许我们通过多个方法调用来构建最终的字符串,而不是一次性传入所有的字符串内容。另一个例子是流式 API,如 Java 8 的 Stream
API,它允许通过链式调用来构建复杂的查询。通过将构建过程与表示分离,建造者模式提高了代码的可读性和可维护性,同时也使得代码更加易于扩展和重用。
推荐阅读
- Spring 三级缓存
- 深入了解 MyBatis 插件:定制化你的持久层框架
- Zookeeper 注册中心:单机部署
- 【JavaScript】探索 JavaScript 中的解构赋值
- 深入理解 JavaScript 中的 Promise、async 和 await