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)