Fluent Builder Pattern vs Constructor

Tuesday, October 2, 2018

By: Chris Dunn

Design patterns are important when developing applications. When people first discover GOF design patterns, they either reject them or are eager to rewrite their code base to make use of the new concepts. The same way I would caution about rejecting Design Patterns out of hand just beause they are trendy, I wouldn't rewrite for the sake of doing something new.

I personally like the Fluent interface we find in LINQ, Entity Framework and other libraries. I first read about the interface from Martin Fowler.  The pattern employs method chaining to provide a clean and easy to read logic flow, and just makes me feel good to implement. But I always have to ask myself if the benefits are worth the extra code for the builder? Can I solve the same problem with a comprehensive constructor call?

Now, let me state that this all depends on what you're building and the complexity of the process and resulting object. So I clarify that as with most things "It depends on your situation". But that is also my point. Don't force a specific Design Pattern when it doesn't fit or isn't worth the trade off.

Here is a simple class representing a House. It has five properties that can be set to customize the House.

    public class House
    {
        public int Floors { get; set; }
        public int Bedrooms { get; set; }
        public bool LivingRoom { get; set; }
        public bool Kitchen { get; set; }
        public string Roof { get; set; }

        public House()
        {

        }


}

A Fluent Builder for the House might look something like the following. Each method returns the HouseBuilder so I can continue making calls. The method Build takes all of those properties and creates and returns a new House instance.

public class HouseBuilder
        {
            public int floors;
            public int bedrooms;
            public bool livingroom;
            public bool kitchen;
            public string roof;

            public HouseBuilder Floors(int value)
            {
                this.floors = value;
                return this;
            }

            public HouseBuilder Bedrooms(int value)
            {
                this.bedrooms = value;
                return this;
            }

            public HouseBuilder HasLivingRoom()
            {
                this.livingroom = true;
                return this;
            }
            public HouseBuilder HasKitchen()
            {
                this.kitchen = true;
                return this;
            }

            public HouseBuilder Roof(string value)
            {
                this.roof = value;
                return this;
            }

            public House Build()
            {
                var house = new House();
                house.Floors = this.floors;
                house.Bedrooms = this.bedrooms;
                house.LivingRoom = this.livingroom;
                house.Kitchen = this.kitchen;
                house.Roof = this.roof;
                return house;
            }
        }

Using the HouseBuilder would look something like this in code. It's nice, clean and easy to understand and read. Just don't forget all the HomeBuilder code from above that is required to support the following clean call.

class Program
    {
        static void Main(string[] args)
        {
            House fluentHouse = new House.Builder()
                .Floors(3)
                .Bedrooms(4)
                .HasKitchen()
                .HasLivingRoom()
                .Roof("Metal")
                .Build();

   
    }

Now, let's say we don't use the Fluent Builder pattern and just rely on the standard constructor with named, optional parameters with default values.

        public House(int floors = 0, int bedrooms = 0, bool livingroom= false, bool kitchen = false, string roof = "")
        {
            this.Floors = floors;
            this.Bedrooms = bedrooms;
            this.LivingRoom = livingroom;
            this.Kitchen = kitchen;
            this.Roof = roof;
        }

Using the constructor to initialize the class, here is the code we need to create a new House. If you compare it to the HouseBuilder class, it's a lot less code. Not only do we remove the entire Builder class, the call to the constructor is still pretty easy to understand and read.

class Program
    {
        static void Main(string[] args)
        {
            House ctorHouse = new House(floors: 3, 
                kitchen: true, livingroom: true, roof: "Metal");
        }


    }


Now I know I've given a somewhat simple scenario here and in cases where the Build process is more complex or object being build requires something more, you and I both might come to a different conclusion.

The take away point is to make sure you are not making your code more complex than it needs to be, for the sake of specific Design Patterns.  Sometimes the simplest solution is the best.

Tags: c# design patterns fluent

Copyright 2019 Cidean, LLC. All rights reserved.

Proudly running Umbraco 7. This site is responsive with the help of Foundation 5.