0x01: Introduction to the Builder pattern
Separating the construction of a complex object from its representation allows the same construction process to create different representations.
Let’s say the construction of an object is complex and requires many steps. You can use the Builder pattern to separate the two steps of building an object from assembling it as an object. The construction part (Builder) and the organization part (Director) realize the decoupling of the construction and assembly.
The main roles are as follows:
Builder: Specifies an abstract interface for creating parts of a product object, typically implemented by subclasses;
ConcreteBuilder: a ConcreteBuilder that implements all methods defined by an abstract class and returns a constructed product object;
Director: the Director who arranges the assembly sequence of existing modules and then tells Builder to start building;
Product: represents a complex object being constructed. The ConcreteBuilder creates an internal representation of the product and defines its assembly process, including classes that define the components, including interfaces that assemble them into the final product.
0x02: Builder pattern implemented
Product: The Product to be built
public class Product { private List<String> parts = new ArrayList<String>(); public void addPart(String part) { parts.add(part); } public void show(){ if(! parts.isEmpty()){ parts.forEach(e -> { System.out.println( e ); }); }}}Copy the code
Director: Calls specific builders for product builds
public class Director { public void construct(Builder builder) { builder.buildPartA(); builder.buildPartB(); }}Copy the code
Builder: The Builder abstract interface
public interface Builder { void buildPartA(); Void buildPartB(); // Product getResult(); // The result after the assembly product is built}Copy the code
ConcreteBuilder: Concrete builders exist for every product class that has the same interface or abstract class.
public class ConcreteBuilder1 implements Builder { private Product product = new Product(); @override public void buildPartA() {product.addPart("ConcreteBuilder1>> Builder1 "); } @override public void buildPartB() {product.addPart("ConcreteBuilder1>> part B"); } @override public Product getResult() {return Product; }}Copy the code
public class ConcreteBuilder2 implements Builder { private Product product = new Product(); @override public void buildPartA() {product.addPart("ConcreteBuilder2>> Buildera "); } @override public void buildPartB() {product.addPart("ConcreteBuilder2>> builder2 "); } @override public Product getResult() {return Product; }}Copy the code
Builder mode tests the code
public class Client { public static void main(String[] args) { Director director = new Director(); Builder builder1 = new ConcreteBuilder1(); Builder builder2 = new ConcreteBuilder2(); Construct (Builder1); // The conductor uses ConcreteBuilder1 to build the concrete director. Construct (builder1); Product product1 = builder1.getResult(); product1.show(); Construct (Builder2); // The conductor uses ConcreteBuilder2 to build the concrete director. Construct (builder2); Product product2 = builder2.getResult(); product2.show(); }}Copy the code
You can see that the builder pattern has the following characteristics:
Good encapsulation: The builder shields the client from the details of the internal composition of the product, and the client does not care about how each specific product is implemented internally.
In line with the open and close principle
Easy control of detail risk: Since the builders are independent of each other, it is possible to refine the construction process without any impact on other modules.
0x03: Builder mode is used in the JDK
In the JDK, the most classic uses of builder mode are StringBuilder and StringBuffer. The main difference between the two classes is that StringBuilder threads are not safe, and StringBuffer threads are safe. The StringBuilder model is used in the JDK.
The Appendable interface defines multiple Append methods (abstract methods). Appendable is the Abstract Builder that defines the abstract methods
public interface Appendable {
Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;
}
Copy the code
AbstractStringBuilder AbstractStringBuilder AbstractStringBuilder AbstractStringBuilder AbstractStringBuilder AbstractStringBuilder AbstractStringBuilder AbstractStringBuilder Cannot instantiate
abstract class AbstractStringBuilder implements Appendable, CharSequence { @Override public AbstractStringBuilder append(CharSequence s) { if (s == null) return appendNull(); if (s instanceof String) return this.append((String)s); if (s instanceof AbstractStringBuilder) return this.append((AbstractStringBuilder)s); return this.append(s, 0, s.length()); } @Override public AbstractStringBuilder append(CharSequence s, int start, int end) { if (s == null) s = "null"; if ((start < 0) || (start > end) || (end > s.length())) throw new IndexOutOfBoundsException( "start " + start + ", end " + end + ", s.length() " + s.length()); int len = end - start; ensureCapacityInternal(count + len); for (int i = start, j = count; i < end; i++, j++) value[j] = s.charAt(i); count += len; return this; } @Override public AbstractStringBuilder append(char c) { ensureCapacityInternal(count + 1); value[count++] = c; return this; } // omit}Copy the code
A StringBuilder acts as both a Director and a ConcreteBuilder. AbstractStringBuilder implements a construction method. And StringBuilder inherits AbstractStringBuilder
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence { @Override public StringBuilder append(String str) { super.append(str); return this; } // other omit}Copy the code
AbstractStringBuilder class AbstractStringBuilder class AbstractStringBuilder class AbstractStringBuilder class AbstractStringBuilder class The object returned by the StringBuilder class is the currently created object this itself (Product).
In addition, MyBatis framework also use a large number of builder mode, if you want to know what MyBatis framework use builder mode, you can read the source of MyBatis.