1. 简介

参考:https://zhuanlan.zhihu.com/p/58093669

建造者模式也属于创建型模式,他提供了一种创建对象的最佳方式。
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的创建过程和细节隐藏起来)。

2. 使用场景

使用场景:当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

当一个类的构造函数参数超过 4 个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象。 例如我们现在有如下一个类计算机类 Computer,其中 cpu 与 ram 是必填参数,而其他 3 个是可选参数,那么我们如何构造这个类的实例呢,通常有两种常用的方式:

  1. public class Computer {
  2. private String cpu;//必须
  3. private String ram;//必须
  4. private int usbCount;//可选
  5. private String keyboard;//可选
  6. private String display;//可选
  7. }

1、折叠构造函数模式(telescoping constructor pattern ),这个我们经常用,如下代码所示:

  1. public class Computer {
  2. ...
  3. public Computer(String cpu, String ram) {
  4. this(cpu, ram, 0);
  5. }
  6. public Computer(String cpu, String ram, int usbCount) {
  7. this(cpu, ram, usbCount, "罗技键盘");
  8. }
  9. public Computer(String cpu, String ram, int usbCount, String keyboard) {
  10. this(cpu, ram, usbCount, keyboard, "三星显示器");
  11. }
  12. public Computer(String cpu, String ram, int usbCount, String keyboard, String display) {
  13. this.cpu = cpu;
  14. this.ram = ram;
  15. this.usbCount = usbCount;
  16. this.keyboard = keyboard;
  17. this.display = display;
  18. }
  19. }

2、Javabean 模式。

  1. public class Computer {
  2. ...
  3. public String getCpu() {
  4. return cpu;
  5. }
  6. public void setCpu(String cpu) {
  7. this.cpu = cpu;
  8. }
  9. public String getRam() {
  10. return ram;
  11. }
  12. public void setRam(String ram) {
  13. this.ram = ram;
  14. }
  15. public int getUsbCount() {
  16. return usbCount;
  17. }
  18. ...
  19. }

那么这两种方式有什么弊端呢?
第一种主要是使用及阅读不方便。可以想象一下,当你要调用一个类的构造函数时,你首先要决定使用哪一个,然后里面又是一堆参数,如果这些参数的类型很多又都一样,你还要搞清楚这些参数的含义,很容易就传混了。。。那酸爽谁用谁知道。
第二种方式在构建过程中对象的状态容易发生变化,造成错误。因为那个类中的属性是分步设置的,所以就容易出错。
为了解决这两个痛点,builder 模式就横空出世了。

3. 具体实现

  1. 在 Computer 中创建一个静态内部类 Builder,然后将 Computer 中的参数都复制到 Builder 类中。
  2. 在 Computer 中创建一个 private 的构造函数,参数为 Builder 类型。
  3. 在 Builder 中创建一个 public 的构造函数,参数为 Computer 中必填的那些参数,cpu 和 ram。
  4. 在 Builder 中创建设置函数,对 Computer 中那些可选参数进行赋值,返回值为 Builder 类型的实例。
  5. 在 Builder 中创建一个 build() 方法,在其中构建 Computer 的实例并返回。

代码如下:

  1. @Data
  2. public class Computer {
  3. private final String cpu;//必须
  4. private final String ram;//必须
  5. private final int usbCount;//可选
  6. private final String keyboard;//可选
  7. private final String display;//可选
  8. private Computer(Builder builder){
  9. this.cpu=builder.cpu;
  10. this.ram=builder.ram;
  11. this.usbCount=builder.usbCount;
  12. this.keyboard=builder.keyboard;
  13. this.display=builder.display;
  14. }
  15. public static class Builder {
  16. private final String cpu;//必须
  17. private final String ram;//必须
  18. private int usbCount;//可选
  19. private String keyboard;//可选
  20. private String display;//可选
  21. public Builder(String cpu,String ram){
  22. this.cpu=cpu;
  23. this.ram=ram;
  24. }
  25. public Builder setUsbCount(int usbCount) {
  26. this.usbCount = usbCount;
  27. return this;
  28. }
  29. public Builder setKeyboard(String keyboard) {
  30. this.keyboard = keyboard;
  31. return this;
  32. }
  33. public Builder setDisplay(String display) {
  34. this.display = display;
  35. return this;
  36. }
  37. public Computer build(){
  38. return new Computer(this);
  39. }
  40. }
  41. }
  42. public class Clent {
  43. public static void main(String[] args) {
  44. Computer computer = new Computer.Builder("因特尔", "三星")
  45. .setDisplay("三星24寸")
  46. .setKeyboard("罗技")
  47. .setUsbCount(2)
  48. .build();
  49. System.out.println(computer);
  50. }
  51. }

结果如下:
image.png

4. 传统实现

构建者模式 UML 图如下所示:
image.png
如上图所示,builder 模式有4个角色。

  • Product: 最终要生成的对象,例如 Computer 实例。
  • Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()。
  • ConcreteBuilder: Builder 的实现类。
  • Director: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法 void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品。

1、目标 computer 类。

@Data
public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选

    public Computer(String cpu, String ram) {
        this.cpu = cpu;
        this.ram = ram;
    }
}

2、抽象构建者类。

public abstract class ComputerBuilder {
    public abstract void setUsbCount();
    public abstract void setKeyboard();
    public abstract void setDisplay();

    public abstract Computer getComputer();
}

3、实体构建者类,可以根据要构建的产品种类产生多了实体构建者类,这里我们需要构建两种品牌的电脑,苹果电脑和联想电脑,所以我们生成了两个实体构建者类。

public class MacComputerBuilder extends ComputerBuilder{
    private Computer computer;

    public MacComputerBuilder(String cpu, String ram) {
        computer = new Computer(cpu, ram);
    }

    @Override
    public void setUsbCount() {
        computer.setUsbCount(2);
    }

    @Override
    public void setKeyboard() {
        computer.setKeyboard("苹果键盘");
    }

    @Override
    public void setDisplay() {
        computer.setDisplay("苹果显示器");
    }

    @Override
    public Computer getComputer() {
        return computer;
    }
}

...联想省略...

4、指导者类。

public class ComputerDirector {
    public void makeComputer(ComputerBuilder builder){
        builder.setUsbCount();
        builder.setDisplay();
        builder.setKeyboard();
    }
}

5、客户端使用。

public class client {
    public static void main(String[] args) {
        ComputerDirector director=new ComputerDirector();//1
        ComputerBuilder builder=new MacComputerBuilder("I5处理器","三星125");//2
        director.makeComputer(builder);//3
        Computer macComputer=builder.getComputer();//4
        System.out.println("mac computer:"+macComputer.toString());

        ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222");
        director.makeComputer(lenovoBuilder);
        Computer lenovoComputer=lenovoBuilder.getComputer();
        System.out.println("lenovo computer:"+lenovoComputer.toString());
    }
}

6、查看结果。
image.png

5. 优缺点

优点

  • 产品的建造和表示分离,实现了解耦。
  • 将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰。
  • 具体的建造者类之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库的代码,符合开闭原则。

缺点

  • 创建的产品一般具有较多的共同点,其组成部分相似:如果产品之间差异性很大,不适用于建造者模式。

[

](https://blog.csdn.net/qq_42219004/article/details/107029055)