设计模式之 ==> 建造者设计模式

一、什么是建造者(Builder)设计模式

  将一个复杂对象的构建过程和它的表示分离,使得同样的构建过程可以创建不同的表示。

  建造者模式可以将一个产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。

  如果我们使用了建造者模式,那么用户只需要指定需要建造的类型就可以得到它们,而具体的建造过程和细节就不需要知道了。

二、建造者模式的使用场景

  它主要是用于创建一些复杂的对象,这些对象的内部构建的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。

  怎么来理解这句话呢?举个例子:我们要创建一组不同类型产品,这些产品都有很多属性,创建过程又有很多道工序,但创建的流程(工序)大体上是一致的。如果没有使用建造者模式的时候,我们得紧盯创建的每一个步骤,生怕该步骤不对或者缺少了某一个步骤,并且每一个产品对象都得一步一步盯着,这样效率低下且容易出错。使用了建造者模式后,会有一个 Builder类(或接口)指定创建产品各个步骤(各个部分)的一个抽象类或接口,一个 Director类,实现 Builder类(或接口),它是一个指挥者,根据需求来创建产品。另外,还有一个甚至多个 ConcreteBuilder类,它们是具体的创建者,用于创建不同类型的产品,也需要实现 Builder类(或接口)。我们来看一下下面这张图就清晰了:

三、建造者模式写法举例

首先,先来一个 Product 类,包括产品的各种属性的描述,包括:产品名、长、宽、高、厚度、颜色等等。

public class Product {

  private String name;
  private Long length;
  private Long wide;
  private Long high;
  private Long thickness;
  private String color;

  public String getName() {
    return name;
  }

  public Product setName(String name) {
    this.name = name;
    return this;
  }

  public Long getLength() {
    return length;
  }

  public Product setLength(Long length) {
    this.length = length;
    return this;
  }

  public Long getWide() {
    return wide;
  }

  public Product setWide(Long wide) {
    this.wide = wide;
    return this;
  }

  public Long getHigh() {
    return high;
  }

  public Product setHigh(Long high) {
    this.high = high;
    return this;
  }

  public Long getThickness() {
    return thickness;
  }

  public Product setThickness(Long thickness) {
    this.thickness = thickness;
    return this;
  }

  public String getColor() {
    return color;
  }

  public Product setColor(String color) {
    this.color = color;
    return this;
  }

  @Override
  public String toString() {
    return "Product{" +
            "name='" + name + '\'' +
            ", length=" + length +
            ", wide=" + wide +
            ", high=" + high +
            ", thickness=" + thickness +
            ", color='" + color + '\'' +
            '}';
  }
}
Product

再来一个 Builder 接口,描述如何制造 Product 对象的各种属性的方法。

public interface ProductBuilder {

  String buildProductName();

  Long buildLength();

  Long buildWide();

  Long buildHigh();

  Long buildThickness();

  String buildColor();
}
ProductBuilder

然后,再来两个不同的产品类型,分别设定产品的产品名、长、宽、高、厚度、颜色等属性的值。

public class ProductA implements ProductBuilder {

  @Override
  public String buildProductName() {
    System.out.println("产品A");
    return "产品A";
  }

  @Override
  public Long buildLength() {
    System.out.println("长度100");
    return 100L;
  }

  @Override
  public Long buildWide() {
    System.out.println("宽度50");
    return 50L;
  }

  @Override
  public Long buildHigh() {
    System.out.println("高度20");
    return 20L;
  }

  @Override
  public Long buildThickness() {
    System.out.println("厚度5");
    return 5L;
  }

  @Override
  public String buildColor() {
    System.out.println("红色");
    return "红色";
  }
}
ProductA
public class ProductB implements ProductBuilder {

  @Override
  public String buildProductName() {
    System.out.println("产品B");
    return "产品B";
  }

  @Override
  public Long buildLength() {
    System.out.println("长度500");
    return 500L;
  }

  @Override
  public Long buildWide() {
    System.out.println("宽度200");
    return 200L;
  }

  @Override
  public Long buildHigh() {
    System.out.println("高度20");
    return 20L;
  }

  @Override
  public Long buildThickness() {
    System.out.println("厚度5");
    return 5L;
  }

  @Override
  public String buildColor() {
    System.out.println("黄色");
    return "黄色";
  }
}
ProductB

最后,就是指挥者 Director 类,负责建造产品,先获取到产品的产品名、长、宽、高、厚度、颜色等属性的值,然后把这些属性塞入 Product 对象对应的属性当中。

public class ProductDirector {

  private ProductBuilder builder;

  public ProductDirector(ProductBuilder builder) {
    this.builder = builder;
  }

  public Product createProduct() {
    return new Product()
            .setName(builder.buildProductName())
            .setLength(builder.buildLength())
            .setWide(builder.buildWide())
            .setHigh(builder.buildHigh())
            .setThickness(builder.buildThickness())
            .setColor(builder.buildColor());
  }
}
ProductDirector

我们来看下客户端调用和返回结果

public class App {

  @Test
  public void test01(){
    ProductDirector productA = new ProductDirector(new ProductA());
    Product product1 = productA.createProduct();
    System.out.println(product1);
    System.out.println("-----------------------------------------");
    ProductDirector productB = new ProductDirector(new ProductB());
    Product product2 = productB.createProduct();
    System.out.println(product2);
  }
}

返回结果:

从结果可以看到:我们成功的制造了两个属性不一样的产品,但是如果我们还需要建造第三类产品 ProductC,则还需要添加一个 ProductC类来实现 ProductBuilder 接口,如果还需要添加呢,有成百上千个呢,显然这样还是太麻烦。我们考虑能不能让客户端自己来设定想要建造什么样的 Product 对象,所有属性都由客户端自己来设定,这样就可以大大的简化我们的代码。

四、简化实现

public class User {
  private String name;
  private Integer age;
  private String info;
  private String password;
  private String balance;

  private User(Builder builder) {
    this.name = builder.name;
    this.age = builder.age;
    this.info = builder.info;
    this.password = builder.password;
    this.balance = builder.balance;
  }

  public static class Builder {
    private String name;
    private Integer age;
    private String info;
    private String password;
    private String balance;

    public static Builder of() {
      return new Builder();
    }

    public Builder name(String name) {
      this.name = name;
      return this;
    }

    public Builder age(Integer age) {
      this.age = age;
      return this;
    }

    public Builder info(String info) {
      this.info = info;
      return this;
    }

    public Builder password(String password) {
      this.password = password;
      return this;
    }

    public Builder balance(String balance) {
      this.balance = balance;
      return this;
    }

    public User build() {
      return new User(this);
    }
  }

  @Override
  public String toString() {
    return "User{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", info='" + info + '\'' +
            ", password='" + password + '\'' +
            ", balance='" + balance + '\'' +
            '}';
  }
}
User

这次我们需要建造的是 User 对象,它有name、age、info、password、balance 五个属性。在它的内部我们加一个静态的内部类 Builder,这个静态内部类有和 User 类一样的五个属性,这个静态内部类就负责获取这五个属性的值,然后传给 User 对象对应的属性,从而来生成User对象。那么,这五个属性的值从哪里来呢?可以从客户端传入,客户端想给每个属性什么值都可以(只要类型正确),这样对于客户端来说,我想制造什么样的 User 对象都由客户端自己决定,不用预先写好对应的类了。我们来看一下客户端调用:

public class App {

  @Test
  public void test01() {
    User user = User.Builder.of()
            .name("大牛")
            .age(25)
            .info("大牛 info")
            .password("123456")
            .balance("大牛 balance")
            .build();
    System.out.println(user);
  }
}

这样,我们客户端调用起来就非常方便且灵活,也大大节省了代码量。

posted on 2020-07-02 16:08  破解孤独  阅读(219)  评论(0编辑  收藏  举报

导航