The 23 design patterns we say are actually more than a dozen commonly used in actual development, which can be structurally divided into three categories (creation pattern, behavior pattern, and structure pattern). Today we are going to talk about creative design patternsBuilder model
See what the Builder pattern is and how and under what circumstances it can be used. When a class has many constructor arguments, and some of these arguments are optional, you can consider using the builder pattern.
We looked at factory patterns earlier, and factory patterns are part of the creation pattern category. Similar to the builder mode, the builder mode is recommended if the build product has many attributes.
What is the Builder pattern
Separating the construction of a complex object from its representation allows the same construction process to create different representations. Multiple parts or components can be assembled into an object but produce different results. Let’s use code to actually use an example:
The old method
Let’s first define the test class
@Getter
@Setter
@NoArgsConstructor
public class Question {
// The name of the topic
private String questionName;
/ / topic
private String questionType;
/ / knowledge
private String questionKnowledge;
// The url of the video
private String videoUrl;
// The duration of the video
private String videoTime;
public Question(String questionName) {
this.questionName = questionName;
}
public Question(String questionName, String questionType) {
this.questionName = questionName;
this.questionType = questionType;
}
public Question(String questionName, String questionType, String questionKnowledge) {
this.questionName = questionName;
this.questionType = questionType;
this.questionKnowledge = questionKnowledge;
}
public Question(String questionName, String questionType, String questionKnowledge, String videoUrl) {
this.questionName = questionName;
this.questionType = questionType;
this.questionKnowledge = questionKnowledge;
this.videoUrl = videoUrl;
}
public Question(String questionName, String questionType, String questionKnowledge, String videoUrl, String videoTime) {
this.questionName = questionName;
this.questionType = questionType;
this.questionKnowledge = questionKnowledge;
this.videoUrl = videoUrl;
this.videoTime = videoTime; }}Copy the code
There are many kinds of questions, such as video questions, games, general questions and so on. Let’s take the general and video questions for a moment. In this case we use a lot of if judgments to create different types of questions like this:
public class Test {
public static void main(String[] args) {
String name = "General topic";
Question question = getQuestion(name);
System.out.println(JSONUtil.parse(question));
}
private static Question getQuestion(String name) {
Question question = new Question();
if("General topic".equals(name)){
question.setQuestionName("Fill in the blanks");
question.setQuestionType("1");
question.setQuestionKnowledge("2");
}
if("Video title".equals(name)){
question.setQuestionName("Preview video");
question.setQuestionType("2");
question.setQuestionKnowledge("3");
question.setVideoUrl("http://www.baidu.com");
question.setVideoTime("23");
}
returnquestion; }}Copy the code
Here we can see that depending on the type of question requested, we can also create exactly the topic we want, but a topic attribute can not only have such a few attributes, in addition to the future to add more questions should be extended one by one if? If you do that, your colleagues who will inherit the code will be in disgrace.
Optimize a wave with builder mode
- To create our abstract Builder class, we create different objects by building different abstract methods.
public abstract class QuestionBuilder {
/** * Create a normal test */
public abstract void getNormalQestion(a);
/** * Create a video problem */
public abstract void getVideoQestion(a);
/** * Construct a game problem */
public abstract void getGameQestion(a);
/ * * *@returnCreate the corresponding title and return */
public abstract Question buildQuestion(a);
}
Copy the code
- Create a concrete builder class. Implement assignment to the abstract method of the abstract builder class to achieve the object we need to create different properties.
public class QuestionCreater extends QuestionBuilder {
protected Question question;
@Override
public void getNormalQestion(a) {
question = new Question();
question.setQuestionName("Fill in the blanks");
question.setQuestionType("1");
question.setQuestionKnowledge("2");
}
@Override
public void getVideoQestion(a) {
question = new Question();
question.setQuestionName("Preview video");
question.setQuestionType("2");
question.setQuestionKnowledge("3");
question.setVideoUrl("http://www.baidu.com");
question.setVideoTime("23");
}
@Override
public void getGameQestion(a) {
// Set the game attributes
}
@Override
public Question buildQuestion(a) {
returnquestion; }}Copy the code
- Create a tutorial class that instructs QuestionCreater to create the corresponding object. I understand that this class is not necessary.
public class QuestionDirector {
private QuestionBuilder questionBuilder;
public QuestionDirector(QuestionBuilder questionBuilder) {
this.questionBuilder = questionBuilder;
}
// Create a normal test
public Question normalQ(a){
questionBuilder.getNormalQestion();
return questionBuilder.buildQuestion();
}
// Create a video problem
public Question videoQ(a){
questionBuilder.getVideoQestion();
returnquestionBuilder.buildQuestion(); }}Copy the code
- Let’s test it on the client side
QuestionBuilder questionBuilder = new QuestionCreater();
QuestionDirector questionDirector = new QuestionDirector(questionBuilder);
Question question = questionDirector.normalQ();
Question question2 = questionDirector.videoQ();
System.out.println(JSONUtil.parse(question));
System.out.println(JSONUtil.parse(question2));
// Remove the tutorial class and create it directly
QuestionBuilder questionBuilderWithOutDirector = new QuestionCreater();
questionBuilderWithOutDirector.getNormalQestion();
Question question3 = questionBuilderWithOutDirector.buildQuestion();
System.out.println(JSONUtil.parse(question3));
Copy the code
Output result:
- {“questionKnowledge”:”2″,”questionName”:” fill in the blank “,”questionType”:”1″}
- {” videoUrl “:” www.baidu.com “, “questionKnowledge” : “3”, “questionName” : “preview video”, “videoTime” : “23”, “questionType” : “2”}
- {“questionKnowledge”:”2″,”questionName”:” fill in the blank “,”questionType”:”1″}
Writing this code in builder mode makes it more readable and easier to extend later without having to fix existing objects and, alas, decouple the different types of problems.
Let’s do another example
Again, if it has many constructors, different constructors will create different objects. For example, if it is the title of the adaptation class, it will need to assign values to the properties of the corresponding video class. Then we can logically adapt to the builder model. We create an abstract title builder:
@NoArgsConstructor
public abstract class AbstractQuestionBuilder {
protected Question question;
public AbstractQuestionBuilder(Question question) {
this.question = question;
}
public AbstractQuestionBuilder setQuestionName(String questionName){
question.setQuestionName(questionName);
return this;
}
public AbstractQuestionBuilder setQuestionType(String questionType){
question.setQuestionType(questionType);
return this;
}
public AbstractQuestionBuilder setQuestionKnowledge(String questionKnowledge){
question.setQuestionKnowledge(questionKnowledge);
return this;
}
public AbstractQuestionBuilder setVideoUrl(String videoUrl){
question.setVideoUrl(videoUrl);
return this;
}
public AbstractQuestionBuilder setVideoTime(String videoTime){
question.setVideoTime(videoTime);
return this;
}
public Question build(a){
returnquestion; }}Copy the code
Add a default create class
public class DefaultQuestionBuilder extends AbstractQuestionBuilder {}Copy the code
That’s it. So how do we use it? Very simple
Question question = new DefaultQuestionBuilder()
.setQuestionName("Fill in the blanks").setQuestionType("1").setQuestionKnowledge("2").build();
Copy the code
With the above two examples, I believe you understand what the Builder pattern is.
Application of the Builder pattern
- StringBuilder
Our most commonly used StringBuilder class has the most direct application of the Builder pattern:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
Copy the code
Let’s see if the append method looks a lot like our example.
- beanDefinitionBuilder
There is also the construction class of the BeanDefinition key class of the commonly used Spring Framework bean
public AbstractBeanDefinition getBeanDefinition(a) {
this.beanDefinition.validate();
return this.beanDefinition;
}
public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
builder.beanDefinition.setBeanClassName(beanClassName);
return builder;
}
public static BeanDefinitionBuilder genericBeanDefinition(Class
beanClass) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
builder.beanDefinition.setBeanClass(beanClass);
return builder;
}
Copy the code
The difference between builder mode and factory mode
As I understand it, Builder mode is basically the same as Factory mode, and builder mode has only one more “guidance” role than factory mode. If you remove this class from the Builder pattern, the rest can be viewed as a simple factory pattern.
Builder mode benefits
- First, the Builder pattern is very encapsulated. Using the Builder pattern can effectively encapsulate changes. In scenarios using the Builder pattern, the general product class and the builder class are relatively stable. Therefore, encapsulating the main business logic in the guidance class can achieve good stability for the whole.
- Second, the Builder pattern is easy to extend. If there is a new requirement, it can be done by implementing a new builder class, essentially without modifying previously tested code, and thus without introducing risk to the original functionality.
Application of the Builder pattern to real business projects
Many of you have seen this before. The interface is used to filter the list of searched data by option (name, branch, discipline, grade). This time is very suitable to use the builder pattern to create a filter class, defined in the screening of class member variables of each filter condition, because the number of filter condition is uncertain, for example, I just want to search by name, I just want to search according to grade, or I want to think again, according to the campus to search by name, and so on. At this time, you can set different filtering conditions to the Builder to construct a filter object that meets the expectations, and then pass the filter object.
Author’s note: Welcome to pay attention to the author’s official account, regularly share IT Internet, finance, education and other work experience, life experience, welcome to exchange.