概述
The intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.
将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示
使用场景
当一个类的构造参数个数超过了4个,而且这些参数有些是可选的参数,考虑使用构造者模式;
当创建复杂对象的算法应该独立与该对象的组成部分以及它们的装配方式时;
当构造过程中允许被构造的对象有不同的表示时。
Builder设计模式中涉及到的参与者
Builder
为创建一个Product对象的各个部件指定抽象接口。
ConcreteBuilder
实现Builder的接口以构造和装配该产品的个部件。
定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建
提供一个检索产品的接口。
构造一个使用Builder接口的对象即在指导者的调用下创建产品实例
Director
Product
表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
包含定义组成部件的类,包括将这些部件装配成最中产品的接口。
其实,在实际使用时,可以根据需要对参与者进行简化或删减,最小结构应该至少包括Builder和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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 public class User { private final String firstName; private final String lastName; private final int age; private final String phone; private final String address; private User (UserBuilder builder) { this .firstName = builder.firstName; this .lastName = builder.lastName; this .age = builder.age; this .phone = builder.phone; this .address = builder.address; } public String getFirstName () { return firstName; } public String getLastName () { return lastName; } public int getAge () { return age; } public String getPhone () { return phone; } public String getAddress () { return address; } @Override public String toString () { return "User: " + this .firstName + ", " + this .lastName + ", " + this .age + ", " + this .phone + ", " + this .address; } public static class UserBuilder { private final String firstName; private final String lastName; private int age; private String phone; private String address; public UserBuilder (String firstName, String lastName) { this .firstName = firstName; this .lastName = lastName; } public UserBuilder age (int age) { this .age = age; return this ; } public UserBuilder phone (String phone) { this .phone = phone; return this ; } public UserBuilder address (String address) { this .address = address; return this ; } public User build () { User user = new User (this ); validateUserObject(user); return user; } private void validateUserObject (User user) { } } }
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 26 27 28 29 30 31 32 33 34 public static void main (String[] args) { User user1 = new User .UserBuilder("Lokesh" , "Gupta" ) .age(30 ) .phone("1234567" ) .address("Fake address 1234" ) .build(); System.out.println(user1); User user2 = new User .UserBuilder("Jack" , "Reacher" ) .age(40 ) .phone("5655" ) .build(); System.out.println(user2); User user3 = new User .UserBuilder("Super" , "Man" ) .build(); System.out.println(user3); }
JDK源码中的实现
Lombok中 @Builder注解内部实现 1 2 3 4 5 6 7 @Builder public class User { private final Integer code = 200 ; private String username; private String password; }
Builder内部帮我们做了什么
创建一个名为ThisClassBuilder的内部静态类,并具有和实体类形同的属性(称为构建器)。
在构建器中:对于目标类中的所有的属性和未初始化的final字段,都会在构建器中创建对应属性。
在构建器中:创建一个无参的default构造函数。
在构建器中:对于实体类中的每个参数,都会对应创建类似于setter的方法,只不过方法名与该参数名相同。 并且返回值是构建器本身(便于链式调用),如上例所示。
在构建器中:一个build()方法,调用此方法,就会根据设置的值进行创建实体对象。
在构建器中:同时也会生成一个toString()方法。
在实体类中:会创建一个builder()方法,它的目的是用来创建构建器。
编译后 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 26 27 28 29 30 31 32 public class User { private String username; private String password; User(String username, String password) { this .username = username; this .password = password; } public static User.UserBuilder builder () { return new User .UserBuilder(); } public static class UserBuilder { private String username; private String password; UserBuilder() {} public User.UserBuilder username (String username) { this .username = username; return this ; } public User.UserBuilder password (String password) { this .password = password; return this ; } public User build () { return new User (this .username, this .password); } public String toString () { return "User.UserBuilder(username=" + this .username + ", password=" + this .password + ")" ; } } }