建造者模式

场景

​ 当需要生产一辆汽车时,我们需要为其装配发动机、轮胎、座椅等等部件,这个装配过程是比较复杂的而且也需要较高的组装技术。而建造者模式(Builder Pattern)就是为了将部件与组装分离开。

概念

​ 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

  与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程。

​ 建造模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心。

建造者模式结构组成

  • Product: 表示被构造的复杂对象,其中包含需要构建的部件属性。
  • Builder: 创建一个产品对象的各个部件指定抽象接口。
  • ConcreteBuilder: 实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示。
  • Director: 调用具体建造者角色以创建产品对象。

下面以构建一辆汽车为例,写示例代码:

  1. Product角色:组装一辆汽车首先的有各种配件,如发动机、轮胎、座椅等。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class Car{
    public String engine;
    public String tyre;
    public String seat;
    public Car(){
    }
    public String getEngine() {
    return engine;
    }
    public void setEngine(String engine) {
    this.engine = engine;
    }
    public String getTyre() {
    return tyre;
    }
    public void setTyre(String tyre) {
    this.tyre = tyre;
    }
    public String getSeat() {
    return seat;
    }
    public void setSeat(String seat) {
    this.seat = seat;
    }
    }
  2. Builder角色:知道了所需配件后,就需要生产配件了,定义一个生产配件的抽象建造者接口。

    1
    2
    3
    4
    5
    public interface Builder {
    String buildEngine();
    String buildTyre();
    String buildSeat();
    }
  3. ConcreteBuilder角色:实现抽象的 建造者接口生成具体的建造者,并开始生产具体的配件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class CarBuilder implements Builder{
    @Override
    public String buildEngine() {
    // 生产发动机
    return "发动机";
    }

    @Override
    public String buildTyre() {
    // 生产轮胎
    return "轮胎";
    }

    @Override
    public String buildSeat() {
    // 生产座椅
    return "座椅";
    }
    }
  4. Director角色:在生产出配件后,由指导者指导组装配件生成汽车。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class CarDirector {
    CarBuilder cb;
    public CarDirector(CarBuilder cb){
    this.cb=cb;
    }
    public Car constructCar(){
    Car car=new Car();
    car.setEngine(cb.buildEngine());
    car.setTyre(cb.buildTyre());
    car.setSeat(cb.buildSeat());
    return car;
    }
    }
  5. 最终得到一辆汽车:

    1
    2
    3
    4
    5
    6
    7
    8
    public class Client {

    public static void main(String[] args) {
    CarDirector carDirector=new CarDirector(new CarBuilder());
    Car car=carDirector.constructCar();
    System.out.println(car.getEngine()+car.getTyre()+car.getSeat());
    }
    }

其他

Lombok中有一个注解@builder就是建造者模式拉~

对所有属性的setter都封闭,这种方式最优雅,也更符合封装的原则,不对外公开属性的写操作!

1
2
3
4
5
6
7
8
9
10
@Builder(toBuilder = true)
@Getter
public class UserInfo {
private String name;
private String email;

@MinMoney(message = "金额不能小于0.")
@MaxMoney(value = 10, message = "金额不能大于10.")
private Money price;
}

赋值新对象

1
2
3
4
UserInfo userInfo = UserInfo.builder()
.name("zzl")
.email("bgood@sina.com")
.build();

修改原对象的属性值

toBuilder=true:代表能够修改原对象的属性值

1
2
3
4
userInfo = userInfo.toBuilder()
.name("OK")
.email("zgood@sina.com")
.build();