Builder建造者模式

273 阅读2分钟

Builder建造者模式

适合的场景

对象的装配比较复杂时,一般来说是指对象本身字段比较多,有些字段必需要指定,有些字段则是可选的。在Grpc中使用的非常多,Grpc方法入参采用builder模式,通过protobuf文件生成这类代码生成也变得方便,而不用生成各种各样的构造器。

优势

  • 减少对象使用者的负担,将对象本身和对象的构建分离开来,不直接使用对象的构造器进行创建。
  • 对象本身可不提供setter方法,让对象是一个不可变类,在多线程环境下也更安全。
  • 提供流式Api,让代码书写更加方便。

关键点

  • 对象本身不对外暴露构造器,而是通过静态内部类Builder来实现。提供静态方法将Builder暴露给外部。
  • Builer类中必须参数用构造器来填充,非必选参数用单独的api来设置,并返回Builer对象本身
  • Builder在build方法进行对象的生成,一般直接调用私有的构造函数。

Demo

下面是服务发现场景中对一个服务实例对象的构造,话不多说,上代码。

 import java.util.Objects;
 import java.util.UUID;
 ​
 /**
  * buildr模式
  * @author puyujie
  * @version 1.0.0
  * @since 2022/11/05 21:59
  */
 public class ServerInstance {
   // 必填参数
   private final String name;
   // 必填参数
   private final String address;
 ​
   // 可选参数
   private final String id;
   // 可选参数
   private final Integer port;
   // 可选参数
   private final Integer sslPort;
 ​
   public static Builder builder(String name, Integer port) {
     return new Builder(name, port);
   }
 ​
   // 私有构造函数,外部不允许访问
   private ServerInstance(String name, String id, String address, Integer port, Integer sslPort) {
     // id为null,给一个默认值
     this.id = Objects.isNull(id) ? UUID.randomUUID().toString() : id;
     this.name = name;
     this.address = address;
     this.port = port;
     this.sslPort = sslPort;
   }
 ​
   @Override
   public String toString() {
     return "ServerInstance{" +
         "name='" + name + ''' +
         ", address='" + address + ''' +
         ", id='" + id + ''' +
         ", port=" + port +
         ", sslPort=" + sslPort +
         '}';
   }
 ​
   private static class Builder {
     // 必填参数
     private String name;
     // 必选参数
     private Integer port;
 ​
     // 可选参数
     private String id;
     // 可选参数
     private Integer sslPort;
     // 必填参数
     private String address;
 ​
     // 必须参数用构造器设置
     public Builder(String name, Integer port) {
       this.name = name;
       this.port = port;
     }
 ​
     // 非必选参数用单独的api进行设置
     public Builder id(String id) {
       this.id = id;
       return this;
     }
 ​
     // 非必选参数用单独的api进行设置
     public Builder address(String address) {
       this.address = address;
       return this;
     }
 ​
     // 非必选参数用set方法构造
     public Builder sslPort(Integer port) {
       this.sslPort = port;
       return this;
     }
 ​
     public ServerInstance build() {
       return new ServerInstance(name, id, address, port, sslPort);
     }
   }
 ​
   public static void main(String[] args) {
     System.out.println(ServerInstance.builder("service", 20011).sslPort(200).build());
   }
 }