This is the 10th day of my participation in the August More text Challenge. For details, see: August More Text Challenge


1. Lego for Everything

Lego should be played, some small parts can be put together into a variety of things, basically only you can imagine, there is nothing it can’t do. Lego sets are pieces of different sizes that can be put together to form a finished product such as a castle or a car.

Let’s try to describe this process in code by first defining an abstract class for the part and four concrete part classes:

// Part abstract base class
public abstract class Part {
	protected String specs;/ / specification

	public Part(String specs) {
		this.specs = specs;
	}

	public abstract String description(a);
}

public class Brick extends Part {
	public Brick(String specs) {
		super(specs);
	}

	@Override
	public String description(a) {
		return specs + "Brick"; }}public class Plate extends Part {
	public Plate(String specs) {
		super(specs);
	}

	@Override
	public String description(a) {
		return specs + "Bottom"; }}public class Tile extends Part{
	public Tile(String specs) {
		super(specs);
	}

	@Override
	public String description(a) {
		return specs + "Tiles"; }}public class Gear extends Part{
	public Gear(String specs) {
		super(specs);
	}

	@Override
	public String description(a) {
		return specs + "Gear"; }}Copy the code

Define a Lego kit, which consists of four parts:

@Getter
public class Lego {
	private List<Brick> bricks = new ArrayList<>();
	private List<Plate> plates = new ArrayList<>();
	private List<Tile> tiles = new ArrayList<>();
	private List<Gear> gears = new ArrayList<>();

	Lego(){}

	// Show the kit
	public void show(a) {
		print(bricks);
		print(plates);
		print(tiles);
		print(gears);
	}

	private void print(List<? extends Part> parts) {
		if(! parts.isEmpty()) { System.out.println("(" + parts.get(0).description() + ")" + " x "+ parts.size()); }}}Copy the code

Now that you have the lego kit, you have the parts, how do you put them together? Let the client create its own parts and set them up in the kit? According to Demeter’s law, the client only cares if it gets a Lego kit, it doesn’t care how the kit is put together.

Therefore, we define a builder interface that can build four parts and ultimately produce a suite. In addition, write two more builder implementations, which are: easy set and hard set.

// Lego set builder
public interface Builder {
	// Build the brick
	Builder buildBrick(a);

	// Build the baseboard
	Builder buildPlate(a);

	// Build the tile
	Builder buildTile(a);

	// Build the gear
	Builder buildGear(a);

	Lego build(a);
}

// Suggest a suite
public class SimpleBuilder implements Builder{
	private Lego lego = new Lego();

	@Override
	public Builder buildBrick(a) {
		for (int i = 0; i < 10; i++) {
			lego.getBricks().add(new Brick("2x2"));
		}
		return this;
	}

	@Override
	public Builder buildPlate(a) {
		for (int i = 0; i < 5; i++) {
			lego.getPlates().add(new Plate("3x3"));
		}
		return this;
	}

	@Override
	public Builder buildTile(a) {
		for (int i = 0; i < 15; i++) {
			lego.getTiles().add(new Tile("4x4"));
		}
		return this;
	}

	@Override
	public Builder buildGear(a) {
		for (int i = 0; i < 20; i++) {
			lego.getGears().add(new Gear("1x1"));
		}
		return this;
	}

	@Override
	public Lego build(a) {
		return this.lego; }}// Difficulty kit
public class ComplexBuilder implements Builder{
	private Lego lego = new Lego();

	@Override
	public Builder buildBrick(a) {
		for (int i = 0; i < 100; i++) {
			lego.getBricks().add(new Brick("2x2"));
		}
		return this;
	}

	@Override
	public Builder buildPlate(a) {
		for (int i = 0; i < 50; i++) {
			lego.getPlates().add(new Plate("3x3"));
		}
		return this;
	}

	@Override
	public Builder buildTile(a) {
		for (int i = 0; i < 150; i++) {
			lego.getTiles().add(new Tile("4x4"));
		}
		return this;
	}

	@Override
	public Builder buildGear(a) {
		for (int i = 0; i < 200; i++) {
			lego.getGears().add(new Gear("1x1"));
		}
		return this;
	}

	@Override
	public Lego build(a) {
		return this.lego; }}Copy the code

As long as there are builders, one Lego kit can be generated, and different builders can build different kits.

To avoid the need for high-level modules to drill down into the implementation classes inside the builder, create a director class that complicatingly calls the builder to generate suite instances.

public class Director {
	public Lego createSimple(a){
		return new SimpleBuilder()
				.buildBrick()
				.buildPlate()
				.buildTile()
				.buildGear()
				.build();
	}

	public Lego createComplex(a){
		return newComplexBuilder() .buildBrick() .buildPlate() .buildTile() .buildGear() .build(); }}Copy the code

Client call:

public class Client {
	public static void main(String[] args) {
		Director director = new Director();
		Lego simpleLego = director.createSimple();
		System.out.println("Simple Lego Kit :");
		simpleLego.show();

		Lego complexLego = director.createComplex();
		System.out.println("Complex Lego Kit :"); complexLego.show(); Output: Simple Lego Kit: (2x2 bricks) x10(3x3 baseboard) x5(4x4 tiles) x15(1x1 gear) x20Complex Lego Kit: (2x2 bricks) X100(3x3 baseboard) x50(4x4 tiles) x150(1x1 gear) x200
Copy the code

That’s builder mode!

2. Definition of the Builder pattern

Separating the construction of a complex object from its representation allows the same construction process to create different representations.

Builder pattern generic class diagram

  • Product: Product category.
  • Builder: An abstract Builder that defines the assembly steps of a product.
  • ConcreteBuilder: ConcreteBuilder: ConcreteBuilder: ConcreteBuilder: ConcreteBuilder: ConcreteBuilder
  • Director: The order in which each sub-component is built, and ultimately tells the Builder to start building the full object.

The definition of the builder pattern is confusing. What does it mean to “separate the construction of a complex object from its representation”? The abstract Builder is responsible for defining that in order to build a complex object, N subcomponents need to be built first. As for how the concrete Builder builds these subcomponents, the upper layer does not care. This is: separate the construction of a complex object from its representation.

What is “enabling the same build process to create different representations”? As above, the abstract Builder is only responsible for defining the N subcomponents that need to be built before a complex object can be built. This process is fixed, or “same build process.” The details of how builders build sub-components can be different, and directors can build sub-components in different orders, which may have different effects on the final product, known as “different representations”.

3. Advantages of the Builder model

  1. With good encapsulation, the builder pattern eliminates the need for the client to know the building process and components of the product, complying with Demeter’s law.
  2. It’s easy for builders to expand, and in the case of Lego, it’s very easy to implement a ridiculously difficult kit.
  3. Builders can refine the construction process without affecting other modules.

4. Use scenarios of the Builder pattern

  1. A product class is very complex, requires a lot of parameters, and many of these parameters are optional, making it a good fit for the builder pattern.
  2. The same method, different execution order will produce different results (director).
  3. Building a product is a tedious process, and the details of the build can be shielded from the outside world through the builder pattern.

5. To summarize

The downside of using the builder pattern is that it requires additional builder objects to be generated, requires the JVM to open up additional memory space, and puts pressure on the GC, so the builder pattern should not be abused, and should not be used if you are building very simple objects. On the other hand, if a production class is so complex that the client will struggle to build it, you should first consider using the builder pattern to build the object.