Façade on “Builder”

pranilism

Pranil Tunga

Posted on May 16, 2023

Façade on “Builder”

As promised, in this blog we will examine the façade pattern for the builders and how we can use it to make our object creation beautiful. In our previous blog, we learned about the functional approach when creating the builder.

You can probably guess what we are about to create just by looking at the name, but let me explain a little more. In this pattern, we basically try to provide a façade around the functionality, which means that we divide our builders and try to provide separate wrappers (façade) around them to create whole objects with proper segregation.

Let's use an example to better understand this. Assume for the moment that we are working with a view model similar to the one shown in the example below.

{
    "RollNumber":"1",
    "Name":"Virat Kohli",
    "GraduationDetails": {
        "College":"Delhi university",
        "Percentage":"90%"
    },
    "PostGraduationDetails": {
        "College":"Gujrat university",
        "Percentage":"85%"
    }
}
Enter fullscreen mode Exit fullscreen mode

So, this is how our C# model will appear:

public class Details
{
    public string College { get; set; }
    public double Percentage { get; set; }
}

public class Student
{
    public string RollNumber { get; set; }
    public string Name { get; set; }
    public Details GraduationDetails = new Details();
    public Details PostGraduationDetails = new Details();
}
Enter fullscreen mode Exit fullscreen mode

Let's now create a builder to create objects for the Student class; this builder will resemble the following:

public class StudentBuilder
{
    private Student _student = new Student();

    public StudentBuilder WithRollNumber(string rollNumber)
    {
        _student.RollNumber = rollNumber;
        return this;
    }

    public StudentBuilder WithName(string name)
    {
        _student.Name = name;
        return this;
    }

    public StudentBuilder HadGraduationFrom(string college, decimal percentage)
    {
        _student.GraduationDetails.College = college;
        _student.GraduationDetails.Percentage = percentage;
        return this;
    }

    public StudentBuilder HadPostGraduationFrom(string college, decimal percentage)
    {
        _student.PostGraduationDetails.College = college;
        _student.PostGraduationDetails.Percentage = percentage;
        return this;
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, in this scenario, we have a builder to create an object of the Student class, and we have exposed multiple methods to accept details, but this is making our builder so big that there may be a chance that a user can mess up because there is no such logical boundary defined and all functionalities are tied to one class, which can lead to messy code later on, and this is kind of breaking the "Single Responsibility Principle" because we have to modify the builder for multiple reasons.

You might be wondering how façades play a role in this. The simple solution is to divide our Student class into three logical boundaries, with the properties "Name" and "RollNumber" falling under the student's personal details, the student's graduation details, and the student's post graduation details, respectively. If we somehow provide three façades and later bind them to a single builder, then we can very easily separate our code and also achieve the “Single Responsibility Principle”.

Let's construct new facades.

public class StudentBuilder
{
    protected Student student = new Student();

    public StudentPersonalInfoBuilder Personal => new StudentPersonalInfoBuilder(student);
    public StudentGraduationInfoBuilder Graduation => new StudentGraduationInfoBuilder(student);
    public StudentPostGraduationInfoBuilder PostGraduation => new StudentPostGraduationInfoBuilder(student);

    public static implicit operator Student(StudentBuilder builder)
    {
        return builder.student;
    }
}

public class StudentPersonalInfoBuilder : StudentBuilder
{
    public StudentPersonalInfoBuilder(Student student) { this.student = student; }

    public StudentPersonalInfoBuilder WithRollNumber(string rollNumber)
    {
        this.student.RollNumber = rollNumber;
        return this;
    }

    public StudentPersonalInfoBuilder WithName(string name)
    {
        this.student.Name = name;
        return this;
    }
}

public class StudentGraduationInfoBuilder : StudentBuilder
{
    public StudentGraduationInfoBuilder(Student student) { this.student = student; }

    public StudentGraduationInfoBuilder HadGraduationFrom(string college, double percentage)
    {
        this.student.GraduationDetails.College = college;
        this.student.GraduationDetails.Percentage = percentage;
        return this;
    }
}

public class StudentPostGraduationInfoBuilder : StudentBuilder
{
    public StudentPostGraduationInfoBuilder(Student student) { this.student = student; }

    public StudentPostGraduationInfoBuilder HadPostGraduationFrom(string college, double percentage)
    {
        this.student.PostGraduationDetails.College = college;
        this.student.PostGraduationDetails.Percentage = percentage;
        return this;
    }
}
Enter fullscreen mode Exit fullscreen mode

As we just discussed, we have now created three new builders. The "StudentPersonalInfoBuilder" is in charge of initializing the student's personal information, and we are using other builders to initialize the student's graduation information and post-graduation information, respectively.

Final code will look something like this:

namespace Builder.FacadeBuilder
{
    public class Details
    {
        public string College { get; set; }
        public double Percentage { get; set; }
    }

    public class Student
    {
        public string RollNumber { get; set; }
        public string Name { get; set; }

        public Details GraduationDetails = new Details();

        public Details PostGraduationDetails = new Details();
    }

    public class StudentBuilder
    {
        protected Student student = new Student();

        public StudentPersonalInfoBuilder Personal => new StudentPersonalInfoBuilder(student);
        public StudentGraduationInfoBuilder Graduation => new StudentGraduationInfoBuilder(student);
        public StudentPostGraduationInfoBuilder PostGraduation => new StudentPostGraduationInfoBuilder(student);

        public static implicit operator Student(StudentBuilder builder)
        {
            return builder.student;
        }
    }

    public class StudentPersonalInfoBuilder : StudentBuilder
    {
        public StudentPersonalInfoBuilder(Student student) { this.student = student; }

        public StudentPersonalInfoBuilder WithRollNumber(string rollNumber)
        {
            this.student.RollNumber = rollNumber;
            return this;
        }

        public StudentPersonalInfoBuilder WithName(string name)
        {
            this.student.Name = name;
            return this;
        }
    }

    public class StudentGraduationInfoBuilder : StudentBuilder
    {
        public StudentGraduationInfoBuilder(Student student) { this.student = student; }

        public StudentGraduationInfoBuilder HadGraduationFrom(string college, double percentage)
        {
            this.student.GraduationDetails.College = college;
            this.student.GraduationDetails.Percentage = percentage;
            return this;
        }
    }

    public class StudentPostGraduationInfoBuilder : StudentBuilder
    {
        public StudentPostGraduationInfoBuilder(Student student) { this.student = student; }

        public StudentPostGraduationInfoBuilder HadPostGraduationFrom(string college, double percentage)
        {
            this.student.PostGraduationDetails.College = college;
            this.student.PostGraduationDetails.Percentage = percentage;
            return this;
        }
    }

    public class FacadeBuilderMain
    {
        public static void Main(string[] args)
        {
            Student student = new StudentBuilder()
                        .Personal.WithRollNumber("ST001")
                                 .WithName("Virat Kohli")
                        .Graduation.HadGraduationFrom("Delhi University", 90.4)
                        .PostGraduation.HadPostGraduationFrom("Punjab University", 87.57);

            Console.WriteLine(@$"
                Roll Number : {student.RollNumber}  
                Name : {student.Name}
                Graduated from {student.GraduationDetails.College} with {student.GraduationDetails.Percentage}
                Post Graduated from  {student.PostGraduationDetails.College} with {student.PostGraduationDetails.Percentage}          
            ");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Output of the above example

We are using a very unusual method to extract the actual object, and that is by using "implicit" operator overriding, where all of these façades are converted to the "Student" class implicitly. Another thing you might notice is that we are also able to maintain fluency, and that is because we are inheriting the StudentBuilder class in each of our builders.

It is difficult to create a faceted builder with structural types when there is no reference available, but fear not, we can do that by using functions and we can use the "pass by reference" mechanism to get references of structural types, or if your company allows "unsafe" code, then you can simply use pointers to pass references of structural types to façades. However, since in this example we are using classes, and as we know, classes have their own set of references, we can pass them directly and share references to façades.


As we discussed in all blogs related to “Builder Pattern," we can use builders to decorate our object creation, and we can format our code to generate objects. Here comes the end of our blog, and this is also the end of Builder Patterns. In coming blogs, we will discuss more “creational” patterns.

Happy Coding…!!!

💖 💪 🙅 🚩
pranilism
Pranil Tunga

Posted on May 16, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Adapter Design Pattern
designpatterns Adapter Design Pattern

May 16, 2023

“Builder Design Pattern”
designpatterns “Builder Design Pattern”

May 16, 2023

Stepwise “Builder”
designpatterns Stepwise “Builder”

May 16, 2023

Prototype design pattern
designpatterns Prototype design pattern

May 16, 2023

Façade on “Builder”
designpatterns Façade on “Builder”

May 16, 2023