In this lesson about the Builder design pattern, or rather two of its types, which apply to the way of creating a class object, and creating an object from other objects. More details in the article.

Description and implementation way

The goal of the builder is to separate the way the object is created from its representation. So the process of creating an object is divided into several parts.

First, I will show an example of a builder pattern on the basis of Fluent Interface, then a classic builder.

The Fluent Interface builder should implement when the constructor has more than four or five parameters, we create a builder class, inside this class, which has this constructor with these many parameters.

Examples in which Fluent Interface Builder would be applicable are everywhere where we have constructors that take many parameters, and Classic Builder, for example in software that accepts any input data, converting it and based on input data, creates output data, i.e. in some game where, under the influence of the user’s actions, the game performs specific events, the builder will be here the code that creates specific events in the game depending on the user’s choices.

Builder Fluent Interface

However, we will refer to our example of the Shop, there was such a Client class:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

classClient

{

publicstringFirstName{get;set;}

publicstringLastName{get;set;}

publicstringZipCode{get;set;}

privatedouble_myWallet;

publicdoubleMyWallet{get=>_myWallet;set=>_myWallet=value;}

publicClient(ClientConstructor myconfiguration)

{

FirstName=myconfiguration.firstname;

LastName=myconfiguration.lastname;

ZipCode=myconfiguration.zipcode;

_myWallet=myconfiguration.myWallet;

}

}

publicclassClientConstructor

{

publicstringfirstname;

publicstringlastname;

publicstringzipcode;

publicdoublemyWallet;

}

We are adding a few other variables such as customer’s address, street, house number and city:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

classClient

{

publicstringFirstName{get;set;}

publicstringLastName{get;set;}

publicstringZipCode{get;set;}

privatedouble_myWallet;

publicdoubleMyWallet{get=>_myWallet;set=>_myWallet=value;}

publicstringTown{get;set;}

publicstringStreet{get;set;}

publicintHomeNumber{get;set;}

publicClient(ClientConstructor myconfiguration)

{

FirstName=myconfiguration.firstname;

LastName=myconfiguration.lastname;

ZipCode=myconfiguration.zipcode;

_myWallet=myconfiguration.myWallet;

Town=myconfiguration.town;

Street=myconfiguration.street;

HomeNumber=myconfiguration.homenumber;

}

}

publicclassClientConstructor

{

publicstringfirstname;

publicstringlastname;

publicstringzipcode;

publicdoublemyWallet;

publicstringtown;

publicstringstreet;

publicinthomenumber;

}

It does not look very clear, when we will use the fluent builder here, not only will it be much more readable, but we will also have a separate process of creating customer data from manipulating, representing them if we want to do something with this data later, so now we implement a fluent builder here the method shown below:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

classClient

{

publicstringFirstName{get;set;}

publicstringLastName{get;set;}

publicstringZipCode{get;set;}

privatedouble_myWallet;

publicdoubleMyWallet{get=>_myWallet;set=>_myWallet=value;}

publicstringTown{get;set;}

publicstringStreet{get;set;}

publicintHomeNumber{get;set;}

publicClient(Builder builder)

{

FirstName=builder.firstname;

LastName=builder.lastname;

ZipCode=builder.zipcode;

_myWallet=builder.myWallet;

Town=builder.town;

Street=builder.street;

HomeNumber=builder.homenumber;

}

publicclassBuilder

{

publicstringfirstname;

publicstringlastname;

publicstringzipcode;

publicdoublemyWallet;

publicstringtown;

publicstringstreet;

publicinthomenumber;

publicBuilder FirstName(stringfirstname)

{

this.firstname=firstname;

returnthis;

}

publicBuilder LastName(stringlastname)

{

this.lastname=lastname;

returnthis;

}

publicBuilder ZipCode(stringzipcode)

{

this.zipcode=zipcode;

returnthis;

}

publicBuilder MyWallet(doublemyWallet)

{

this.myWallet=myWallet;

returnthis;

}

publicBuilder Town(stringtown)

{

this.town=town;

returnthis;

}

publicBuilder HomeNumber(inthomenumber)

{

this.homenumber=homenumber;

returnthis;

}

publicBuilder Street(stringstreet)

{

this.street=street;

returnthis;

}

publicClient build()

{

returnnewClient(this);

}

}

}

As you can see, we have separated the saving of customer data from the rest of the logic, and we can control to a greater extent how the object is created.

Also saving data in the “Main” function is much more readable:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

staticvoidMain(string[]args)

{

Client client=newClient.Builder()

.FirstName("Slawomir")

.LastName("Kowalski")

.ZipCode("34 174")

.MyWallet(456.32)

.HomeNumber(23)

.Town("Cambridge")

.Street("botolph lane")

.build();

Console.WriteLine("Data client: "+"\nFirstName: "+client.FirstName+

"\nKowalski: "+client.LastName+

"\nZip code: "+client.ZipCode+

"\nWallet: "+client.MyWallet+

"\nHome number: "+client.HomeNumber+

"\nTown: "+client.Town+

"\nStreet: "+client.Street);

Console.ReadKey();

}

Now you can see what data is saved to the object.

Result:

This is the Builder Fluent Interface, now we’ll do the example of a classic builder.

Classic Builder

Structure

First, let’s see what the UML Builder diagram looks like:

Converter class as you can see, creates instances of individual classes that read different data formats, and here the Reader class is a client who only reads these formats.

An example of a builder can be eg a customer who orders food from a restaurant, look at the picture below:

First, the customer orders a meal, then the report comes to the manager, who then tells the employees who later execute the order together with the delivery to the house. In the code, we will make an example of our store.

Example

Let’s build our store, let’s separate its objects, eg in this way walls, roof, floor, what will it look like in a classic builder?

An example may start a fright at the beginning, but it’s really a simple pattern, you just have to convert it into practice.

I will translate pieces of the whole code one by one, I will give the whole example at the end of the lesson in the source files, because it is long.

The classic builder can be treated as a plan.

The diagram of the created store looks like this:

We add to the Shop class, roof, floor, and wall, then create a store object with the manager in the client, in our case in the Main function, the whole is designed so that the customer can’t see how the store is created, client is commissioning the build shop the builder so relating to our example, Director class, and the client does not care how the store is built, only the finished product is delivered to him.

Let’s see now how it looks in the code, let’s start from the left side of the diagram, ie the Shop, Roof, Floor, Wall classes:

Shop:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

namespaceBuilderShop

{

publicclassShop

{

privateIRoof roof;

privateIFloor floor;

privateIWall wall;

publicvoidSetRoof(IRoof roof)

{

this.roof=roof;

}

publicIRoof GetRoof()

{

returnroof;

}

publicvoidSetFloor(IFloor floor)

{

this.floor=floor;

}

publicIFloor GetFloor()

{

returnfloor;

}

publicvoidSetWall(IWall wall)

{

this.wall=wall;

}

publicIWall GetWall()

{

returnwall;

}

}

}

Floor:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

namespaceBuilderShop

{

publicinterfaceIFloor

{

intLenght{get;set;}

intNumberOfTiles{get;set;}

stringTypeGreatnessTiles{get;set;}

intReturnLenght();

intReturnNumberOfTiles();

stringReturnTypeGreatnessTiles();

voidSetLenght(intLenght);

voidSetNumberOfTiles(intNumberOfTiles);

voidSetTypeGreatnessTiles(stringTypeGreatnessTiles);

}

publicclassFloor:IFloor

{

publicintLenght{get;set;}

publicintNumberOfTiles{get;set;}

publicstringTypeGreatnessTiles{get;set;}

publicintReturnLenght()

{

returnLenght;

}

publicintReturnNumberOfTiles()

{

returnNumberOfTiles;

}

publicstringReturnTypeGreatnessTiles()

{

returnTypeGreatnessTiles;

}

publicvoidSetLenght(intLenght)

{

this.Lenght=Lenght;

}

publicvoidSetNumberOfTiles(intNumberOfTiles)

{

this.NumberOfTiles=NumberOfTiles;

}

publicvoidSetTypeGreatnessTiles(stringTypeGreatnessTiles)

{

this.TypeGreatnessTiles=TypeGreatnessTiles;

}

}

}

Roof:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

namespaceBuilderShop

{

publicinterfaceIRoof

{

intHeight{get;set;}

intReturnHeight();

voidSetHeight(intHeight);

}

publicclassRoof:IRoof

{

publicintHeight{get;set;}

publicintReturnHeight()

{

returnHeight;

}

publicvoidSetHeight(intHeight)

{

this.Height=Height;

}

}

}

Wall:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

namespaceBuilderShop

{

publicinterfaceIWall

{

intThickness{get;set;}

stringColor{get;set;}

intReturnThickness();

stringReturnColor();

voidSetThickness(intThickness);

voidSetColor(stringColor);

}

publicclassWall:IWall

{

publicintThickness{get;set;}

publicstringColor{get;set;}

publicintReturnThickness()

{

returnThickness;

}

publicstringReturnColor()

{

returnColor;

}

publicvoidSetThickness(intThickness)

{

this.Thickness=Thickness;

}

publicvoidSetColor(stringColor)

{

this.Color=Color;

}

}

}

We implement its elements in the shop class, but in the form of interfaces, we stick to the fifth SOLID principle, dependency inversion, class relations should result from abstraction and high-level modules should not depend on low-level modules, the store is a high-level module and the roof, floor, wall they are low-level modules, such a small reminder on the SOLID principles 🙂

Our builder looks like this:

C#

1

2

3

4

5

6

7

publicinterfaceIShopBuilder

{

voidBuildFloor();

voidBuildRoof();

voidBuildWall();

Shop getShop();

}

Is an interface that we implement to the store class we want to build and we want to build a large Tesco store 🙂

It looks like this:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

namespaceBuilderShop

{

classBigShopTesco:IShopBuilder

{

privateShop shop;

publicBigShopTesco()

{

this.shop=newShop();

}

publicvoidBuildFloor()

{

IFloor floor=newFloor();

floor.SetLenght(20);

floor.SetNumberOfTiles(100);

floor.SetTypeGreatnessTiles("Big");

shop.SetFloor(floor);

}

publicvoidBuildRoof()

{

IRoof roof=newRoof();

roof.SetHeight(10);

shop.SetRoof(roof);

}

publicvoidBuildWall()

{

IWall wall=newWall();

wall.SetThickness(1);

wall.SetColor("Green");

shop.SetWall(wall);

}

publicShop getShop()

{

returnshop;

}

}

}

We set in methods the BigShopTesco class parameters sets its elements and write them to the interfaces of the Shop class.

We call the BigShopTesco class methods in our manager, in the ShopDirector class:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

namespaceBuilderShop

{

publicclassShopDirector

{

privateIShopBuilder shopbuilder;

publicShopDirector(IShopBuilder shopbuilder)

{

this.shopbuilder=shopbuilder;

}

publicvoidbuildShop()

{

shopbuilder.BuildFloor();

shopbuilder.BuildRoof();

shopbuilder.BuildWall();

}

publicShop getShop()

{

returnshopbuilder.getShop();

}

}

}

To the constructor of the ShopDirector class we pass the object of the class that we want to create, that is BigShopTesco and we call its methods.