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 definitionProduct
of each abstract interface memberConcreteBuilder
: Inherited fromBuilder
realized creation具体类型的Product
interface for all components, obtain and provide a final product interface.Director
: WithBuilder
internal packaging process to create specific products.
FIG sequence 3.UML
- Client to create a ConcreteBuilder
- Client to create a Director by passing ConcreteBuilder
- Client Using Director construction products
- 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:
DogBuilder
which in addition to the need to achieve IAnimalBuilder
to all the interfaces, also need to provide a GetDog()
method used to create the good Dog
to the outside; the same CatBuilder
is 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 Core
the framework WebHost
created. 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 IPersonBuilder
the interface, in addition Build
to 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 Fluent
way 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 PersonBuilder
up, for implementing IPersonBuilder
specific 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!