The builder pattern --Builder Design Patterns

I. Overview

Builder mode, the Chinese called the builder pattern, also known as generator mode, builder mode, one of the founders design mode. Construction for its separation represent a complex object, such that the same build process can create different representations.

1. Applicability:

  • Creating an object is more complex, there are several ways to create forms when
  • Create complex objects and internal objects and algorithms are relatively independent assembly

FIG class 2.UML

  • Builder: Creating a definition Productof each abstract interface member
  • ConcreteBuilder: Inherited from Builderrealized creation 具体类型的Productinterface for all components, obtain and provide a final product interface.
  • Director: With Builderinternal packaging process to create specific products.

FIG sequence 3.UML

  1. Client to create a ConcreteBuilder
  2. Client to create a Director by passing ConcreteBuilder
  3. Client Using Director construction products
  4. Client use ConcreteBuilder assembled and obtain the final product

Second, examples

Imagine you as a creator, you need to create a variety of animals, such as dogs and cats. View source

1. Before creation, first think good dogs and cats in general what it was like, it is clear that they should have a head, body and feet.

abstract class Animal
{
    public string Head { get; set; }
    public string Body { get; set; }
    public string Foots { get; set; }
    
    public abstract void Display();
}

class Dog : Animal
{
    public override void Display()
    {
        Console.WriteLine("-------------- 狗的基本信息 -------------------");
        Console.WriteLine($"头:{Head}");
        Console.WriteLine($"身体:{Body}");
        Console.WriteLine($"脚:{Foots}");
    }
}

class Cat : Animal
{
    public override void Display()
    {
        Console.WriteLine("-------------- 猫的基本信息 -------------------");
        Console.WriteLine($"头:{Head}");
        Console.WriteLine($"身体:{Body}");
        Console.WriteLine($"脚:{Foots}");
    }
}

2. determine the basic characteristics of animals, and also a clear job to do - create head, body and feet of animals.

interface IAnimalBuilder
{
    void SetHead();
    void SetBody();
    void SetFoots();
}

3. The next step is to consider the details of creating various parts of the dog and cat. But do not worry coding, let's consider one thing:
  DogBuilderwhich in addition to the need to achieve IAnimalBuilderto all the interfaces, also need to provide a GetDog()method used to create the good Dogto the outside; the same CatBuilderis also required to provide a GetCat()method. How many animals of this world? one thousand? Ten thousand? Far more than! In the encoding process it is easy to forget that this method provides a. So we insert a layer of abstraction in the middle of the abstract and concrete Builder Builder IAnimalBuilder<TAnimal>, all ConcreteBuilder inherit from this interface.

interface IAnimalBuilder<TAnimal> : IAnimalBuilder where TAnimal : Animal 
{
    TAnimal GetAnimal();
}

class DogBuilder : IAnimalBuilder<Dog>
{
    private readonly Dog _dog = new Dog();

    public void SetHead()
    {
        _dog.Head = "狗的头";
    }

    public void SetBody()
    {
        _dog.Body = "狗的身体";
    }

    public void SetFoots()
    {
        _dog.Foots = "狗的脚";
    }

    public Dog GetAnimal()
    {
        return _dog;
    }
}

class CatBuilder : IAnimalBuilder<Cat>
{
    private readonly Cat _cat = new Cat();

    public void SetHead()
    {
        _cat.Head = "猫的头";
    }

    public void SetBody()
    {
        _cat.Body = "猫的身体";
    }

    public void SetFoots()
    {
        _cat.Foots = "猫的脚";
    }

    public Cat GetAnimal()
    {
        return _cat;
    }
}

4. Finally, only Director, and it is to plan what things you want to create Builder.

class Director
{
    private readonly IAnimalBuilder _builder;

    public Director(IAnimalBuilder builder)
    {
        _builder = builder;
    }

    public void Construct()
    {
        _builder.SetHead();
        _builder.SetBody();
        _builder.SetFoots();
    }
}

We're done! Then try it

var dogBuilder = new DogBuilder();
var dogDirector = new Director(dogBuilder);
dogDirector.Construct();
dogBuilder.GetAnimal().Display();

var catBuilder = new CatBuilder();
var catDirector = new Director(catBuilder);
catDirector.Construct();
catBuilder.GetAnimal().Display();

Third, the variant

The actual development process, often encounter a need: to create objects, parts of objects can be selected freely set or not set, but the object Once created, you can not make any changes. For example: ASP.NET Corethe framework WebHostcreated. Next, we simulate what Nu Wa made man.
1. Similarly, let's set the basic attributes of a good man

class Person
{
    public string Name { get; set; }
    public int Gender { get; set; }
    public int Age { get; set; }
}

2. Next, we define IPersonBuilderthe interface, in addition Buildto the methods, we have returned IPersonBuilder, are accustomed to use Linq.Net developer, the familiar, the biggest advantage is that it allows us to use Fluentway to write code .

public interface IPersonBuilder
{
    //注意,这里有问题
    Person Build();
    IPersonBuilder SetName(string name);
    IPersonBuilder SetGender(int gender);
    IPersonBuilder SetAge(int age);
}

You find out what the problem? Yes, contrary to one of the five principles of object-oriented - Dependency Inversion (abstract should not rely on specific); moreover, it does not meet the "must not be changed after the object is created," the demand. So, we need to extract an abstraction layer IPersion.

public interface IPerson
{
    string Name { get; }
    int Gender { get; }
    int Age { get; }
}

class Person : IPerson
{
    public string Name { get; set; }
    public int Gender { get; set; }
    public int Age { get; set; }
}

public interface IPersonBuilder
{
    IPerson Build();
    IPersonBuilder SetName(string name);
    IPersonBuilder SetGender(int gender);
    IPersonBuilder SetAge(int age);
}

3. The next step is to build PersonBuilderup, for implementing IPersonBuilderspecific logical interface.

class PersonBuilder : IPersonBuilder
{
    private readonly Person _person = new Person();

    public IPerson Build()
    {
        return _person;
    }

    public IPersonBuilder SetName(string name)
    {
        _person.Name = name;
        return this;
    }

    public IPersonBuilder SetGender(int gender)
    {
        _person.Gender = gender;
        return this;
    }

    public IPersonBuilder SetAge(int age)
    {
        _person.Age = age;
        return this;
    }      
}

//提供一个辅助类,用来帮 Client 创建 PersonBuilder
public class PersonBuilderHelper
{
    public static IPersonBuilder CreatePersonBuilder()
    {
        return new PersonBuilder();
    }
}

4.Ok, you're done! Test it

var person = PersonBuilderHelper.CreatePersonBuilder()
    .SetAge(20)
    .SetName("jjj")
    .Build();
//输出:jjj,0,20
Console.WriteLine($"{person.Name},{person.Gender},{person.Age}");

IV Summary

Classic and variant versions of the differences:

  • Classic tend to build up planning package, Client does not care about the internal logic; and variant version eliminates the Director, Client makes to have more initiative, can freely build.
  • Classic requires Director to build, assemble and use the Builder returns the result; variant version is used directly Builder chain were constructed and assembled returns the result, the structure is more clear.
  • Classic commonly used in the construction of a variety of products is relatively fixed situation, Director species should not be too much, and must adapt to all products; and are more likely to build a variant version of a product, not fixed way to build quite complex situations .

View source

if there are new findings will supplement!

Guess you like

Origin www.cnblogs.com/xiaoxiaotank/p/11022816.html