Start with a picture, and the rest is all up to writing...
<img src="https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/Design Mode.png" style="zoom: 33%;">
introduction
Design pattern collection: http://aphysia.cn/categories/designpattern
If you have used Mybatis
, I believe you are not unfamiliar with the writing of the following code, first create a builder
object, and then call the .build()
function:
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
builder mode that we are going to explain in this article, let us consider it together.
What is the builder mode
The builder pattern is a type of design pattern that separates the construction of a complex object from its representation, so that the same construction process can create different representations. (From Baidu Encyclopedia)
The builder mode is actually a kind of creation mode and one of the 23 design modes. From the above definition, it is rather vague, but we have to admit that when we have the ability to define something in concise terms , We really understand it, because at this time we already know its limits.
The so-called separation of the construction of a complex object from its representation is to abstract the object's builder. The construction process is the same, but different constructors can achieve different representations.
Structure and examples
The builder mode is mainly divided into the following four roles:
- Product (
Product
): the complex object to be constructed by the specific producer - Abstract generator (
Bulider
): An abstract generator is an interface that creates an interface method for each part of a product and a method for returning the product - Concrete builder (
ConcreteBuilder
): According to their own product characteristics, realize the interface corresponding to the abstract builder - Commander (
Director
): Create a complex object to control the specific process
Speaking of this, it may be a bit awkward. After all, all are definitions. From the practical example, let’s take the programmer’s favorite computer as an example. Suppose that we are now producing a variety of computers. The computer has a screen, a mouse, a cpu, and a motherboard. , Disk, memory, etc., we may be able to write it right away:
public class Computer {
private String screen;
private String mouse;
private String cpu;
private String mainBoard;
private String disk;
private String memory;
...
public String getMouse() {
return mouse;
}
public void setMouse(String mouse) {
this.mouse = mouse;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
...
}
In the above example, each attribute uses a separate set
method. If different components of different computers are produced, the specific implementation is not the same. Such a class does not seem to be very elegant to implement, such as Lenovo computers and ASUS computers. The screen construction process is different, and the construction of these components is theoretically part of the computer, we can consider the processing of the pipeline type
Of course, there is another realization, that is, multiple constructors, different constructors with different parameters, to achieve optional parameters:
public class Computer {
private String screen;
private String mouse;
private String cpu;
private String mainBoard;
private String disk;
private String memory;
public Computer(String screen) {
this.screen = screen;
}
public Computer(String screen, String mouse) {
this.screen = screen;
this.mouse = mouse;
}
public Computer(String screen, String mouse, String cpu) {
this.screen = screen;
this.mouse = mouse;
this.cpu = cpu;
}
...
}
The above construction methods of multiple parameters meet the requirements of on-demand construction in theory, but there are still deficiencies:
- If the process of constructing each component is more complicated, then the constructor looks messy
- If there are multiple on-demand construction requirements, there are too many constructors
- Different computer types are constructed, coupled together, and must be abstracted
First of all, we first use the pipeline method to achieve on-demand construction, and we can't overload so many constructors:
public class Computer {
private String screen;
private String mouse;
private String cpu;
private String mainBoard;
private String disk;
private String memory;
public Computer setScreen(String screen) {
this.screen = screen;
return this;
}
public Computer setMouse(String mouse) {
this.mouse = mouse;
return this;
}
public Computer setCpu(String cpu) {
this.cpu = cpu;
return this;
}
public Computer setMainBoard(String mainBoard) {
this.mainBoard = mainBoard;
return this;
}
public Computer setDisk(String disk) {
this.disk = disk;
return this;
}
public Computer setMemory(String memory) {
this.memory = memory;
return this;
}
}
When used, it is constructed like a pipeline, and it can be constructed step by step:
Computer computer = new Computer()
.setScreen("高清屏幕")
.setMouse("罗技鼠标")
.setCpu("i7处理器")
.setMainBoard("联想主板")
.setMemory("32G内存")
.setDisk("512G磁盘");
But the above writing is not elegant enough. Since the construction process may be complicated, why not use a specific class to construct it? In this way, the construction process is separated from the main class, and the responsibilities are more clear. Here, the inner class is fine:
package designpattern.builder;
import javax.swing.*;
public class Computer {
private String screen;
private String mouse;
private String cpu;
private String mainBoard;
private String disk;
private String memory;
Computer(Builder builder) {
this.screen = builder.screen;
this.cpu = builder.cpu;
this.disk = builder.disk;
this.mainBoard = builder.mainBoard;
this.memory = builder.memory;
this.mouse = builder.mouse;
}
public static class Builder {
private String screen;
private String mouse;
private String cpu;
private String mainBoard;
private String disk;
private String memory;
public Builder setScreen(String screen) {
this.screen = screen;
return this;
}
public Builder setMouse(String mouse) {
this.mouse = mouse;
return this;
}
public Builder setCpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder setMainBoard(String mainBoard) {
this.mainBoard = mainBoard;
return this;
}
public Builder setDisk(String disk) {
this.disk = disk;
return this;
}
public Builder setMemory(String memory) {
this.memory = memory;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
When using, use builder
to build. After the build is completed, when calling build, give the specific value to the object we need (here is Computer
):
public class Test {
public static void main(String[] args) {
Computer computer = new Computer.Builder()
.setScreen("高清屏幕")
.setMouse("罗技鼠标")
.setCpu("i7处理器")
.setMainBoard("联想主板")
.setMemory("32G内存")
.setDisk("512G磁盘")
.build();
System.out.println(computer.toString());
}
}
But the above wording, if we construct a variety of computers, the configuration of each computer is different, and the construction process is different, then we must abstract the constructor and turn it into an abstract class.
First we define the product category Computer
:
public class Computer {
private String screen;
private String mouse;
private String cpu;
public void setScreen(String screen) {
this.screen = screen;
}
public void setMouse(String mouse) {
this.mouse = mouse;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
@Override
public String toString() {
return "Computer{" +
"screen='" + screen + '\'' +
", mouse='" + mouse + '\'' +
", cpu='" + cpu + '\'' +
'}';
}
}
Define an abstract construction class for all computer constructions:
public abstract class Builder {
abstract Builder buildScreen(String screen);
abstract Builder buildMouse(String mouse);
abstract Builder buildCpu(String cpu);
abstract Computer build();
}
First construct a Lenovo computer. The Lenovo computer must implement its own constructor. Each computer always has its own special features:
public class LenovoBuilder extends Builder {
private Computer computer = new Computer();
@Override
Builder buildScreen(String screen) {
computer.setScreen(screen);
return this;
}
@Override
Builder buildMouse(String mouse) {
computer.setMouse(mouse);
return this;
}
@Override
Builder buildCpu(String cpu) {
computer.setCpu(cpu);
return this;
}
@Override
Computer build() {
System.out.println("构建中...");
return computer;
}
}
With the builder, we need a commander who is responsible for building our specific computer:
public class Director {
Builder builder = null;
public Director(Builder builder){
this.builder = builder;
}
public void doProcess(String screen,String mouse,String cpu){
builder.buildScreen(screen)
.buildMouse(mouse)
.buildCpu(cpu);
}
}
When using it, we only need to build builder
first, and then pass builder
to the commander, who is responsible for the specific construction. After the construction is completed, the builder calls the .build()
method to create a computer.
public class Test {
public static void main(String[] args) {
LenovoBuilder builder = new LenovoBuilder();
Director director = new Director(builder);
director.doProcess("联想屏幕","游戏鼠标","高性能cpu");
Computer computer = builder.build();
System.out.println(computer);
}
}
Print result:
构建中...
Computer{screen='联想屏幕', mouse='游戏鼠标', cpu='高性能cpu'}
The above is actually the complete builder mode, but most of what we usually use is to directly call the builder Builder
, all the way to set()
, and finally build()
to create an object.
scenes to be used
What are the benefits of building this model? The first thing that comes to mind should be to decouple the construction process. If the construction process is very complicated, take it out and write it separately, which is clear and concise. Secondly, the construction of each part can actually be created independently, without multiple construction methods, and the construction work is handed over to the builder, not the object itself. Professional people do professional things. Similarly, the builder mode is also more suitable for different construction methods or construction sequences, which may produce different construction results.
But there are still shortcomings. The Builder
object needs to be maintained. If there are not many commonalities between multiple products, the abstract builder will lose its role. If there are many product types, then define too many build classes to achieve this change, and the code will become more complicated.
Recently, I used GRPC
in the company. Almost all the objects in it are based on the builder mode. The chained construction is really comfortable and elegant. The code is written for people to see. All the design patterns we do are for Extend, decouple, and prevent code from being passed on by word of mouth.
[Profile of the author] :
Qin Huai, [161af76fcbac64 Qinhuai Grocery Store ], the road of technology is not at a time, the mountains are high and the rivers are long, even if it is slow, it will never stop. Personal writing direction: Java source code analysis,
JDBC
, Mybatis
, Spring
, redis
, distributed,
sword refers to Offer,
LeetCode
etc., write each article carefully, do not like the title of the series of articles , I cannot guarantee that what I have written is completely correct, but I guarantee that what I have written has been practiced or searched for information. I hope to correct any omissions or errors.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。