This article has participated in the Denver Nuggets Creators Camp 3 “More Productive writing” track, see details: Digg project | creators Camp 3 ongoing, “write” personal impact.

Aliases: Builder mode, Builder

A, intentions

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

The generator pattern enables us to create complex objects in steps. This pattern allows you to generate objects of different types and forms using the same creation code.


Second, motivation

In programming, we sometimes face the creation of “a complex object”, which is usually composed of sub-objects of each part with certain algorithms. The parts of this complex object face drastic changes due to changing requirements, but the algorithms they combine are relatively stable.

The question is: what to do about it? How to provide a “encapsulation mechanism” to isolate changes in “parts of complex objects” so that the “stable build algorithm” in the system does not change with this change in requirements?

There are many houses in PUBG. The simplest house (toilet) consists of a door, four walls, a set of Windows, and a floor and a roof. What about the more complicated ones, some of them have cabins in them, some of them have two stories and stairs in them, roof shapes; The material that door, wall uses, these are based on a house to expand processing, so how to do?

1. The easiest way to do this is to extend the “house” base class and create a series of subclasses that cover all parameter combinations. You’ll find lots of different types of houses and combinations of different types. And any additional parameter (adding a new material door) in the future will make the structure more complex. As a result, creating a subclass for every possible object can cause the program to become too complex.

2. Alternatively, instead of subclassing, you can create a super constructor in the “house” base class that contains all possible arguments and use it to control the generation of house objects. This approach does avoid subclassing, but it makes most arguments useless in general. The drawback is that constructors with a large number of input parameters also have a drawback: they don’t need to be used all the time.

Solution: — The generator pattern The generator generation pattern suggests pulling the object construction code out of the production class and putting it in a separate object called the generator.

This pattern divides the construction of an object into a set of steps, such as “Create door” and “Create wall.” Each time you create an object, you need to perform a series of steps on the generator object. The point is that you don’t need to call all the steps, you just need to call the steps needed to create the configuration for a particular object.

When you need to create different forms of products, some of the construction steps may be implemented differently. (For example: wood toilets have wood walls, stone toilets have stone walls)

In this case, you can create several different generators that implement the same set of creation steps in different ways. You can then use these generators in the creation process (e.g., create stone floors, regenerate four stone walls… This sequence calls constructs) to generate different types of objects (houses);

Summary: The generator pattern lets you create complex objects step by step. The generator does not allow other objects to access the product being created.


Three, the structure is

  1. The Builder interface declares product construction steps common to all type generators.
  2. Concrete Builders provide different implementations of the construction process. Concrete generators can also construct products that do not follow a common interface.
  3. Products are the final generated objects. Products built by different generators need not belong to the same class hierarchy or interface.
  4. The Director class defines the order in which construction steps are invoked so that you can create and reuse specific product configurations.
  5. The Client must associate a generator object with the master class.

In general, you only need to make a one-time correlation with the parameters of the main class constructor. The master class can then use the generator object for all subsequent construction tasks. But there is another way in which the client passes the generator object to the master class fabricator method. In this case, you can use a different generator each time you produce a product using the master class.


Four, advantages and disadvantages

Advantages:

  • Single responsibility principle. You can separate complex construction code from the business logic of the product.
  • Use the generator pattern to avoid the telescopic Constructor. (Overloaded constructors for various parameters)
  • You can create objects step by step, defer the creation step, or run the creation step recursively.
  • You can reuse the same manufacturing code when creating different forms of products.

Disadvantages:

  • This pattern requires multiple new classes and increases the overall complexity of the code.

Five, application scenarios

Applicability:

  • When algorithms that create complex objects should be independent of the components of that object and how they are composed.
  • When you want to use code to create different forms of products (such as stone or wood houses).
  • If you need to create various forms of products, the manufacturing process is similar and only the details differ.

Reference:

  • The abstract factory pattern addresses changing requirements for “family objects.”
  • The generator pattern addresses “object part” requirement changes.

Six, code implementation

Implementation method:

  1. Clearly define common steps to ensure they can be manufactured in all forms. Otherwise you won’t be able to use the pattern any further.
  2. Declare these steps in the basic generator interface.
  3. Create a concrete generator class for each form of product and implement its construction steps.

Don’t forget to implement methods that get the constructed result object. You cannot declare this method in a generator interface because the products of different generator constructs may not have a common interface, so you will not know the type of object returned by this method. However, if all products are in a single class hierarchy, you can safely add methods to get generated objects in the base interface. 4. Consider creating a director class. It can use the same generator object to encapsulate multiple ways of constructing products. 5. The client code creates both generator and master objects. Before construction can begin, the client must pass the generator object to the master object. Typically, the client only needs to call the master class constructor once. The master class uses the generator object for all subsequent manufacturing tasks. Alternatively, the client can pass the generator object directly to the master class’s manufacturing method. 6. Construction results can be obtained directly from the master class only if all products follow the same interface. Otherwise, the client should get the result of the build through the generator.

Sample code:

  1. Create a generator
  2. Create house foundations, floors, walls, doors, Windows, roof and other construction steps
 /// <summary>
 ///Interface section-->Base class generator
 /// </summary>
 public abstract class Builder
 {
     // Create floors, walls, doors, Windows, and roofs
     public abstract void BuildFloor();
     public abstract void BuildWall();
     public abstract void BuildDoor();
     public abstract void BuildWindows();
     public abstract void BuildHouseCeiling();

     // Create a house
     public abstract House GetHouse();
 }


 /// <summary>
 ///FangWuJi class-->Actual usage is modified as needed (not necessarily abstract classes or interfaces)
 /// </summary>
 public abstract class House
 {
 	// todo... Add concrete implementations as needed
 }

 // Simulate each subpart abstraction
 public abstract class Floor{}public abstract class Wall{}public abstract class door{}public abstract class Windows{}public abstract class HouseCeiling{}Copy the code
  1. A form of concrete class generator — an example of a concrete implementation of a house on an island map (generating exclusive doors, Windows, walls and other elements of the island)

Ps: set abstract factory mode –> Subsequent expansion of desert and snow map can be copied and modified according to the following code logic expansion

/// <summary>
///Island house builder
/// </summary>
public class IslandHouseBuilder : Builder
{
    IslandHouse islandHouse;

    // Create a new island house through the structure
    public IslandHouseBuilder()
    {
        islandHouse = new IslandHouse();
    }
 	// todo.. Implement as needed
    public override void BuildDoor()
    {
        // The simulation creates an island door for the specified house
        // Implement it in the IslandDoor class
        // Returns a specified gate by calling the specified method
        islandHouse.IslandDoor = new IslandDoor();
        Console.WriteLine("-- created an island map floor --");
    }

    public override void BuildFloor()
    {
        islandHouse.IslandFloor = new IslandFloor();
        Console.WriteLine("-- created an island map door --");
    }

    public override void BuildHouseCeiling()
    {
        islandHouse.IslandHouseCeiling = new IslandHouseCeiling();
        Console.WriteLine("-- created an island map roof --");
    }

    public override void BuildWall()
    {
        islandHouse.IslandWall = new IslandWall();
        Console.WriteLine("-- created an island map wall --");
    }

    public override void BuildWindows()
    {
        islandHouse.IslandWindows = new IslandWindows();
        Console.WriteLine("-- created an island map window --");
    }

    public override House GetHouse()
    {
        // Perform some specific operations on the resulting house

        Console.WriteLine("-- Can be combined at will according to demand --");
        Console.WriteLine("-- got a house with an island map --");

        return newIslandHouse(); }}/// <summary>
///Island home
/// </summary>
public class IslandHouse : House
{
	// Perform a simple relationship simulation
    public Door IslandDoor;
    public Floor IslandFloor;
    public Wall IslandWall;
    public Windows IslandWindows;
    public HouseCeiling IslandHouseCeiling;
}

// todo... Implement doors, Windows, walls, floors and roofs on the island map
public class IslandDoor : door{}public class IslandFloor : Floor{}public class IslandWall : Wall{}public class IslandWindows : Windows{}public class IslandHouseCeiling : HouseCeiling{}Copy the code

4. Simulation game supervisor,

public class GameManager
{
	// todo... Expand as needed
    public static House CreateHouse(Builder builder)
    {
        // Create a floor
        builder.BuildFloor();
        / / four walls
        builder.BuildWall();
        builder.BuildWall();
        builder.BuildWall();
        builder.BuildWall();
        // Door, roof
        builder.BuildDoor();
        builder.BuildHouseCeiling();

        returnbuilder.GetHouse(); }}Copy the code
  1. Simulate a client call
// Simulate the client
class Program
{
    static void Main(string[] args)
    {
        // Create a house on the island map
        House islandHouse = GameManager.CreateHouse(newIslandHouseBuilder()); Console.ReadKey(); }}Copy the code

Test results:


Design Patterns series of blog posts sample code Engineering: Links