This is the 22nd day of my participation in Gwen Challenge
Design patterns
Builder model
For example, we build a house, the process of building a house is piling, laying walls, capping, the type of house bungalow, building, villa
Our code is written like this
AbsHouse
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.24 13:56 * /
public abstract class AbsHouse {
public abstract void layingFoundation(a);
public abstract void buildWall(a);
public abstract void sealRoof(a);
public void build(a) { layingFoundation(); buildWall(); sealRoof(); }}Copy the code
Bungalow
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.24 13:56 * /
public class Bungalow extends AbsHouse {
@Override
public void layingFoundation(a) {
System.out.println("Bungalow foundation");
}
@Override
public void buildWall(a) {
System.out.println("Bungalow building walls.");
}
@Override
public void sealRoof(a) {
System.out.println("Bungalow roof capping"); }}Copy the code
main
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.24 13:56 * /
public class Builder {
public static void main(String[] args) {
Bungalow bungalow = newBungalow(); bungalow.build(); }}Copy the code
In this way, the coupling is strong, and the building process of the house is all encapsulated together, so the house and the building process need to be decoupled
Product Role House
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.23 14:46 * /
public class House {
private String foundation;
private String wall;
private String roof;
public String getFoundation(a) {
return foundation;
}
public void setFoundation(String foundation) {
this.foundation = foundation;
}
public String getWall(a) {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoof(a) {
return roof;
}
public void setRoof(String roof) {
this.roof = roof; }}Copy the code
The abstract HouseBuilder
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.23 14:46 * /
public abstract class HouseBuilder {
protected House house = new House();
public abstract void layingFoundation(a);
public abstract void buildWall(a);
public abstract void sealRoof(a);
public House buildHouse(a) {
returnhouse; }}Copy the code
It was built by Bungalow
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.24 13:56 * /
public class Bungalow extends HouseBuilder {
@Override
public void layingFoundation(a) {
System.out.println("Bungalow foundation");
}
@Override
public void buildWall(a) {
System.out.println("Bungalow building walls.");
}
@Override
public void sealRoof(a) {
System.out.println("Bungalow roof capping"); }}Copy the code
And another specific builder, Villa
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date 2021.06.24 14:49
*/
public class Villa extends HouseBuilder {
@Override
public void layingFoundation(a) {
System.out.println("Villa foundation");
}
@Override
public void buildWall(a) {
System.out.println("Villas build walls.");
}
@Override
public void sealRoof(a) {
System.out.println("Villa capping"); }}Copy the code
commander
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.23 14:46 * /
public class HouseDirector {
HouseBuilder houseBuilder = null;
public HouseDirector(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public House constructHouse(a) {
houseBuilder.layingFoundation();
houseBuilder.buildWall();
houseBuilder.sealRoof();
returnhouseBuilder.buildHouse(); }}Copy the code
main
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.24 13:56 * /
public class Builder {
public static void main(String[] args) {
Villa villa = new Villa();
HouseDirector houseDirector = new HouseDirector(villa);
House house = houseDirector.constructHouse();
Bungalow bungalow =newBungalow(); houseDirector.setHouseBuilder(bungalow); House house1 =houseDirector.constructHouse(); }}Copy the code
When we add buildings, we just add tallbuildings
package com.wangscaler.builder;
/ * * *@author wangscaler
* @date2021.06.24 13:56 * /
public class TallBuilding extends HouseBuilder {
@Override
public void layingFoundation(a) {
System.out.println("Building foundation");
}
@Override
public void buildWall(a) {
System.out.println("Building walls");
}
@Override
public void sealRoof(a) {
System.out.println("Building capping"); }}Copy the code
The builder pattern in the source code
In the JDK StringBuilder
Let’s open up the source code
package java.lang;
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable.CharSequence
{
/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;
/** * Constructs a string builder with no characters in it and an * initial capacity of 16 characters. */
public StringBuilder(a) {
super(16);
}
/**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the {@code capacity}
* argument is less than {@code0}. * /
public StringBuilder(int capacity) {
super(capacity);
}
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string builder that contains the same characters
* as the specified {@code CharSequence}. The initial capacity of
* the string builder is {@code 16} plus the length of the
* {@code CharSequence} argument.
*
* @param seq the sequence to copy.
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
@Override
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}
/ * * *@throws IndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
@Override
public StringBuilder append(char[] str) {
super.append(str);
return this;
}
/ * * *@throws IndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
@Override
public StringBuilder append(boolean b) {
super.append(b);
return this;
}
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
@Override
public StringBuilder append(int i) {
super.append(i);
return this;
}
@Override
public StringBuilder append(long lng) {
super.append(lng);
return this;
}
@Override
public StringBuilder append(float f) {
super.append(f);
return this;
}
@Override
public StringBuilder append(double d) {
super.append(d);
return this;
}
/ * * *@since1.5 * /
@Override
public StringBuilder appendCodePoint(int codePoint) {
super.appendCodePoint(codePoint);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder replace(int start, int end, String str) {
super.replace(start, end, str);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int index, char[] str, int offset,
int len)
{
super.insert(index, str, offset, len);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, Object obj) {
super.insert(offset, obj);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, char[] str) {
super.insert(offset, str);
return this;
}
/ * * *@throws IndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int dstOffset, CharSequence s) {
super.insert(dstOffset, s);
return this;
}
/ * * *@throws IndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int dstOffset, CharSequence s,
int start, int end)
{
super.insert(dstOffset, s, start, end);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, boolean b) {
super.insert(offset, b);
return this;
}
/ * * *@throws IndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, char c) {
super.insert(offset, c);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, int i) {
super.insert(offset, i);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, long l) {
super.insert(offset, l);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, float f) {
super.insert(offset, f);
return this;
}
/ * * *@throws StringIndexOutOfBoundsException {@inheritDoc} * /
@Override
public StringBuilder insert(int offset, double d) {
super.insert(offset, d);
return this;
}
@Override
public int indexOf(String str) {
return super.indexOf(str);
}
@Override
public int indexOf(String str, int fromIndex) {
return super.indexOf(str, fromIndex);
}
@Override
public int lastIndexOf(String str) {
return super.lastIndexOf(str);
}
@Override
public int lastIndexOf(String str, int fromIndex) {
return super.lastIndexOf(str, fromIndex);
}
@Override
public StringBuilder reverse(a) {
super.reverse();
return this;
}
@Override
public String toString(a) {
// Create a copy, don't share the array
return new String(value, 0, count);
}
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);
s.writeObject(value);
}
/** * readObject is called to restore the state of the StringBuffer from * a stream. */
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
value = (char[]) s.readObject(); }}Copy the code
It turns out that it inherits AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable.CharSequence {
/** * The value is used for character storage. */
char[] value;
/** * The count is the number of characters used. */
int count;
/** * This no-arg constructor is necessary for serialization of subclasses. */
AbstractStringBuilder() {
}
/** * Creates an AbstractStringBuilder of the specified capacity. */
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
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;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
/ * * *@since1.8 * /
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null)
return appendNull();
int len = asb.length();
ensureCapacityInternal(count + len);
asb.getChars(0, len, value, count);
count += len;
return this;
}
// Documentation in subclasses because of synchro difference
@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());
}
private AbstractStringBuilder appendNull(a) {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
@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;
}
public AbstractStringBuilder append(char[] str) {
int len = str.length;
ensureCapacityInternal(count + len);
System.arraycopy(str, 0, value, count, len);
count += len;
return this;
}
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
}
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
}
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("2147483648");
return this;
}
int appendedLength = (i < 0)? Integer.stringSize(-i) +1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
}
public AbstractStringBuilder append(long l) {
if (l == Long.MIN_VALUE) {
append("9223372036854775808");
return this;
}
int appendedLength = (l < 0)? Long.stringSize(-l) +1
: Long.stringSize(l);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Long.getChars(l, spaceNeeded, value);
count = spaceNeeded;
return this;
}
public AbstractStringBuilder append(float f) {
FloatingDecimal.appendTo(f,this);
return this;
}
public AbstractStringBuilder append(double d) {
FloatingDecimal.appendTo(d,this);
return this; }}Copy the code
In the case of the Append method, we see that it is implemented as an abstract class called Appendable
/* * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * /
package java.lang;
import java.io.IOException;
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
So this Appendable is kind of the abstract builder of our builder pattern, where we’re creating abstract methods, so our AbstractStringBuilder is the concrete builder that implements those abstract methods, and the StringBuilder acts as the conductor
Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
Copy the code
And as a concrete builder
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
Copy the code
conclusion
The builder has four roles
- Product role: A concrete object (house) with multiple components (foundation, wall, roof)
- Abstract Builder: An interface that contains abstract methods for creating the various parts of a product (foundations, walls, tops), and generally methods for returning to the final product (buildHouse).
- Specific builder: implement the interface, implement the method of constructing and assembling various parts (foundation, wall, roof)
- Director: Calls the method that builds the part to complete the object creation (assembling the house).
Usage Scenarios:
1. The products created by the builder generally have more in common (the building is based, walled and capped). If the difference is relatively large, it is not suitable for use.
2. Create simple objects using the factory pattern, create complex objects (more than 5 components) using the Builder pattern
3, the same method, different execution sequence, produce different results.
Multiple parts or components can be assembled into an object, but the results are not the same.
5. The product class is very complex, or different calls in the product class have different effects.
6. Initializing an object is extremely complex with many parameters, many of which have default values.
The resources
- JAVA Design Pattern
- Detailed explanation of the Builder model (Bulider model)