Original post: The Builder pattern messing with Java Design Patterns
Builder model
Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.
Separating the construction of a complex object from its representation allows the same construction process to be used to create different representations. Generally speaking, an object creation process is very complex, so we can separate each element creation process from the same construction process to create different objects. You can see the following UML diagram.
Builder pattern UML diagrams
This AbstractPersonBuilder is the same construct as above, and different representations are the PersonOneBuilder and PersonTwoBuilder constructors in the same way here, but the specific implementation is different and different representations are constructed. So it’s the same process of constructing different objects.
Builder mode character
AbstractPersonBuilder (AbstractPersonBuilder) : abstract methods of abstract classes or interfaces, properties of complex objects, that do not involve the creation of concrete object parts;
Concrete builders (PersonOneBuilder and PersonTwoBuilder) : implement abstract builders that externalize the creation of parts of complex objects for different businesses. Provide examples of products after completion of the construction process;
Director: calls on specific builders to create parts of a complex object. The Director does not involve specific product information, but is only responsible for ensuring that the parts of the object are created intact or in a certain order.
Concrete product (Person) : complex object to be created;
Builder mode source dry goods
Source code address: please click me
I’m going to talk about the Builder pattern in three different ways. The first is our original Builder pattern, the second is the one we use for solid objects, and the third is lombok, the most common way we use solid objects.
The first builder model
Use is really above according to the character to build the way, a little like the following two methods responsible point.
Abstract builder
public abstract class AbstractPersonBuilder {
protected Person product = new Person();
public abstract void buildName(a);
public abstract void buildAge(a);
public abstract void buildChildren(a);
public Person build(a) {
returnproduct; }}Copy the code
The first concrete builder
public class PersonOneBuilder extends AbstractPersonBuilder {
public void buildName(a) {
product.setName("Old one");
}
public void buildAge(a) {
product.setAge(44);
}
public void buildChildren(a) {
product.setChildren(Lists.newArrayList("Little one")); }}Copy the code
The second concrete builder
public class PersonTwoBuilder extends AbstractPersonBuilder {
public void buildName(a) {
product.setName("The two");
}
public void buildAge(a) {
product.setAge(55);
}
public void buildChildren(a) {
product.setChildren(Lists.newArrayList("Two")); }}Copy the code
The Person class acts as product data
public class Person {
private String name;
private int age;
private List<String> children;
@Override
public String toString(a) {
return "Person{" +
"name='" + name + '\' ' +
", age=" + age +
", children=" + children +
'} ';
}
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge(a) {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getChildren(a) {
return children;
}
public void setChildren(List<String> children) {
this.children = children; }}Copy the code
Commander, designates specific builders to use to build objects
public class Director {
private AbstractPersonBuilder builder;
public Director(AbstractPersonBuilder builder) {
this.builder = builder;
}
public void setBuilder(AbstractPersonBuilder builder) {
this.builder = builder;
}
public Person construct(a) {
builder.buildName();
builder.buildAge();
builder.buildChildren();
returnbuilder.build(); }}Copy the code
The sample
@Slf4j
public class Application {
public static void main(String[] args) {
Director director = new Director(new PersonOneBuilder());
Person person = director.construct();
log.info("Person information: {}", person);
director.setBuilder(new PersonTwoBuilder());
person = director.construct();
log.info("Person information: {}", person); }}Copy the code
Results:
The second builder model
The second approach is simpler because we specify only one construct and can also borrow the third-party tool IDEA+Plugins.
You can search in IDEA
Usage:
1. Find the class whose bulid needs to be added. You can view the build by automatically generating shortcut keys
2. According to your own style, you can define the name of bulid, the prefix of each bulid method, and the package name, as shown in the following code.
PersonBuilder The builder used for Person
public final class PersonBuilder {
private String name;
private int age;
private List<String> children;
private PersonBuilder(a) {}public static PersonBuilder builder(a) {
return new PersonBuilder();
}
public PersonBuilder withName(String name) {
this.name = name;
return this;
}
public PersonBuilder withAge(int age) {
this.age = age;
return this;
}
public PersonBuilder withChildren(List<String> children) {
this.children = children;
return this;
}
public Person build(a) {
Person person = new Person();
person.setName(name);
person.setAge(age);
person.setChildren(children);
returnperson; }}Copy the code
The Person class acts as product data
public class Person {
private String name;
private int age;
private List<String> children;
@Override
public String toString(a) {
return "Person{" +
"name='" + name + '\' ' +
", age=" + age +
", children=" + children +
'} ';
}
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge(a) {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getChildren(a) {
return children;
}
public void setChildren(List<String> children) {
this.children = children; }}Copy the code
The sample
@Slf4j
public class Application {
public static void main(String[] args) {
Person wang = PersonBuilder.builder()
.withAge(40)
.withName("Wang")
.withChildren(Lists.newArrayList("Li Yiyi"."Wu Lao SAN"))
.build();
log.info("Lao Wang's message: {}", wang); }}Copy the code
The results are as follows:
The third builder model
The third pattern is much simpler because we borrowed Lombok’s @Builder annotation. Lombok introduced the @superbulider annotation in version 18.2 to solve the problem that inheritance from the @Builder class did not take effect. See the template method pattern in my previous article for more details on how to use the Java design pattern
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String name;
private int age;
private List<String> children;
}
Copy the code
@Slf4j
public class Application {
public static void main(String[] args) {
Person wang = Person.builder()
.age(40)
.name("Wang")
.children(Lists.newArrayList("Li Yiyi"."Wu Lao SAN"))
.build();
log.info("Lao Wang's message: {}", wang); }}Copy the code
Results:
conclusion
The second and third patterns are commonly defined when we frequently manipulate objects such as VO, DO, and DTO. The builders of the first standard mode, in fact itself commander this role is not concerned with specific product realization, relative and a decoupling, for if a new builder implementation, and can be extended, in line with the principle of open and close, but likewise, implements the above advantages, but the downside followed, added a lot of classes, maintenance cost is high, If there are internal changes to the builder, it doesn’t work well for the builder model. In general, there are many usage scenarios. So StringBulider is actually one of those. RedisCacheManagerBuilder is defined in this article extending the TTL and key names of the Redis cache in spring-boot’s Spring-cache, and Feign’s Builder is commonly used and will be covered later.
Welcome to attention