建造者模式,即==使用多个简单的对象一步一步构建成一个复杂的对象==
主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;
1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。3、建造者模式在创建复杂对象时非常有用,特别是当对象的构建过程涉及多个步骤或参数时。它可以提供更好的灵活性和可维护性,同时使得代码更加清晰可读。
1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
2、JAVA 中的 StringBuilder。
- 产品(Product):表明需要构建的产品对象
- 抽象建造者(Builder):抽象出来的构建者类,用于定==义创建对象所需的步骤==以及创建的步骤的调用过程
- 具体建造者(ConcreteBuilder):抽象建造者的具体实现,对于不同的创建过程可以用不同的类进行实现
- 指挥者(Director)**:使用 Builder 的类,提供给调用方**使用,调用方通过使用指挥者来获取产品
// 产品类,定义产品的三个部分
public class Product {
private Object part1;
private Object part2;
private Object part3;
public void setPart1(Object part1) {
this.part1 = part1;
}
public void setPart2(Object part2) {
this.part2 = part2;
}
public void setPart3(Object part3) {
this.part3 = part3;
}
@Override
public String toString() {
return "Product{" +
"part1=" + part1 +
", part2=" + part2 +
", part3=" + part3 +
'}';
}
}
满足多扩展、少实现的开发原则
// 抽象建造者类,构建了一个产品对象,并定义了构建产品三个部分所需要的三个方法以及获取产品的方法
public abstract class Builder {
protected Product product = new Product();
public abstract void buildPart1();
public abstract void buildPart2();
public abstract void buildPart3();
public abstract Product getProduct();
}
// 具体建造者 1
public class ConcreteBuilder1 extends Builder{
@Override
public void buildPart1() {
product.setPart1("builder 1 set part 1.");
}
@Override
public void buildPart2() {
product.setPart2("builder 1 set part 2.");
}
@Override
public void buildPart3() {
product.setPart3("builder 1 set part 3.");
}
@Override
public Product getProduct() {
System.out.println("builder 1 build product.");
return product;
}
}
// 具体建造者 2
public class ConcreteBuilder2 extends Builder {
@Override
public void buildPart1() {
product.setPart1("builder 2 set part 1.");
}
@Override
public void buildPart2() {
product.setPart2("builder 2 set part 2.");
}
@Override
public void buildPart3() {
product.setPart3("builder 2 set part 3.");
}
@Override
public Product getProduct() {
System.out.println("builder 2 build product.");
return product;
}
}
// 指挥者对象
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public Product construct() {
builder.buildPart1();
builder.buildPart2();
builder.buildPart3();
Product product = builder.getProduct();
return product;
}
}
public static void main(String[] args) {
//调用方通过调用指挥者(传入的建造者不同,则创建的过程不一样)来创建产品,屏蔽了创建产品的过程
Director director1 = new Director(new ConcreteBuilder1());
Product product1 = director1.construct();
System.out.println(product1);
System.out.println("==================================");
Director director2 = new Director(new ConcreteBuilder2());
Product product2 = director2.construct();
System.out.println(product2);
}
builder 1 build product.
Product{part1=builder 1 set part 1., part2=builder 1 set part 2., part3=builder 1 set part 3.}
==================================
builder 2 build product.
Product{part1=builder 2 set part 1., part2=builder 2 set part 2., part3=builder 2 set part 3.}
我们可以看到通过给 Director 对象传入具体的构建者便能够构建出不同的产品对象,并且构建过程对于调用方来说是不可见的。
假设我们要创建一个简单的汽车对象,包含品牌、颜色和引擎类型等属性,使用建造者模式建造该汽车对象
public class Car {
private String brand;
private String color;
private String engineType;
public Car(String brand, String color, String engineType) {
this.brand = brand;
this.color = color;
this.engineType = engineType;
}
// 省略 getter 和 setter 方法
}
public abstract class CarBuilder {
protected Car car;
public void createCar() {
car = new Car();
}
public abstract void buildBrand();
public abstract void buildColor();
public abstract void buildEngineType();
public Car getCar() {
return car;
}
}
public class SedanCarBuilder extends CarBuilder {
@Override
public void buildBrand() {
car.setBrand("Sedan");
}
@Override
public void buildColor() {
car.setColor("Red");
}
@Override
public void buildEngineType() {
car.setEngineType("Gasoline");
}
}
public class SUVCarBuilder extends CarBuilder {
@Override
public void buildBrand() {
car.setBrand("SUV");
}
@Override
public void buildColor() {
car.setColor("Blue");
}
@Override
public void buildEngineType() {
car.setEngineType("Diesel");
}
}
public class CarDirector {
private CarBuilder carBuilder;
public CarDirector(CarBuilder carBuilder) {
this.carBuilder = carBuilder;
}
public void constructCar() {
carBuilder.createCar();
carBuilder.buildBrand();
carBuilder.buildColor();
carBuilder.buildEngineType();
}
public Car getCar() {
return carBuilder.getCar();
}
}
public class Main {
public static void main(String[] args) {
CarBuilder sedanCarBuilder = new SedanCarBuilder();
CarDirector sedanCarDirector = new CarDirector(sedanCarBuilder);
sedanCarDirector.constructCar();
Car sedanCar = sedanCarDirector.getCar();
System.out.println(sedanCar);
CarBuilder suvCarBuilder = new SUVCarBuilder();
CarDirector suvCarDirector = new CarDirector(suvCarBuilder);
suvCarDirector.constructCar();
Car suvCar = suvCarDirector.getCar();
System.out.println(suvCar);
}
}
Car{brand='Sedan', color='Red', engineType='Gasoline'}
Car{brand='SUV', color='Blue', engineType='Diesel'}
通过抽象建造者(CarBuilder)声明了构建汽车的方法,并由具体建造者(SedanCarBuilder和SUVCarBuilder)实现这些方法。指挥者(CarDirector)负责指导具体建造者的建造过程。每个具体建造者都可以按照自己的方式构建汽车对象。这样,我们就可以灵活地创建不同类型的汽车对象。
JDK 中的建造者模式使用最多的就是 StringBuilder 类
StringBuilder 继承自 AbstractStringBuilder,而我们每次在调用 append 方法的时候就是在往 AbstractStringBuilder 类中变量 value 中追加字符
所以此时 AbstractStringBuilder 就对应抽象建造者,StringBuilder 就是具体的建造者,String 对象就是我们所需要的产品。但是此时我们并没有发现 Director,其实此时的 StringBuilder 类同时也充当着 Director 的角色,其 toString() 方法就是返回最终 String 对象。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
……
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
……
}
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
……
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
}
……
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
}
我们在使用 Lombok 时有个基础注解叫 @Builder,使用该注解的类就不用再 new 对象,直接赋值然后调用 build() 方法便能构建对象。其原理就是在使用该注解的类中生成一个静态的内部 Builder类,然后通过调用该内部类的方法给生成的类对象赋值。我们以 Computer 类为例,代码如下:
@Builder
public class Computer {
private String CPU;
private String GPU;
private String memory;
private String motherboard;
private String hardDisk;
}
对代码进行编译后,再看最后生成的代码如下:
public class Computer {
private String CPU;
private String GPU;
private String memory;
private String motherboard;
private String hardDisk;
Computer(String CPU, String GPU, String memory, String motherboard, String hardDisk) {
this.CPU = CPU;
this.GPU = GPU;
this.memory = memory;
this.motherboard = motherboard;
this.hardDisk = hardDisk;
}
public static Computer.ComputerBuilder builder() {
return new Computer.ComputerBuilder();
}
public static class ComputerBuilder {
private String CPU;
private String GPU;
private String memory;
private String motherboard;
private String hardDisk;
ComputerBuilder() {
}
public Computer.ComputerBuilder CPU(String CPU) {
this.CPU = CPU;
return this;
}
public Computer.ComputerBuilder GPU(String GPU) {
this.GPU = GPU;
return this;
}
public Computer.ComputerBuilder memory(String memory) {
this.memory = memory;
return this;
}
public Computer.ComputerBuilder motherboard(String motherboard) {
this.motherboard = motherboard;
return this;
}
public Computer.ComputerBuilder hardDisk(String hardDisk) {
this.hardDisk = hardDisk;
return this;
}
public Computer build() {
return new Computer(this.CPU, this.GPU, this.memory, this.motherboard, this.hardDisk);
}
public String toString() {
return "Computer.ComputerBuilder(CPU=" + this.CPU + ", GPU=" + this.GPU + ", memory=" + this.memory + ", motherboard=" + this.motherboard + ", hardDisk=" + this.hardDisk + ")";
}
}
}
可以看到反编译后内部生成了 ComputerBuilder 类,该类就是用于构建 Computer 对象,因此这也是一个构建者模式。
建造者模式将对象的创建过程和表现分离,并且调用方通过指挥者调用方法对对象进行构建,使得调用方不再关心对象构建过程,构建对象的具体过程可以根据传入类型的不同而改变。通常在实际开发应用中通常会对建造者模式的角色进行阉割,往往只保留真正构建对象的过程。那么有的人就可能会有疑问了,构建者模式最终是获取一个对象,工厂模式也是获取一个对象,这两种模式有什么区别呢?这两种模式都是属于创建型模式,而这两种模式的侧重点不太一样:
1、对象类型:建造者模式用于复杂对象的构建,并且对象中的复杂组件的调用和赋值过程能够自定义;工厂模式创建的对象通常是具体类型或接口的实例
2、对象的组件:建造者模式在构建的过程需要知道对象需要哪些组件,并对组件进行赋值;工厂模式并不关心组件,直接调用方法即可3、构建的过程顺序:从建造者模式的概念上讲,其实建造者模式是在一个**固定的流程下构建的对象,因此强调一定的执行顺序==**,而工厂模式并不关心。但是在开发中往往会忽略掉这部分的执行顺序
优点:
- 分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
- 可以更好地控制构建过程,隐藏具体构建细节。
- 代码复用性高,可以在不同的构建过程中重复使用相同的建造者。
缺点:
- 如果产品的属性较少,建造者模式可能会导致代码冗余。
- 建造者模式增加了系统的类和对象数量。
https://blog.csdn.net/qq_38550836/article/details/125862850