In this post, I am going to discuss with examples the Fluent Interface Design Pattern to use a chain of methods or "Method Chaining" to rapidly create a set of methods that operates/shares the same object. We are going to go over the following points:

  1. What is the Fluent Interface Design Pattern?
  2. What is Method Chaining in C#?
  3. Implementing Fluent Interface and Method Chaining with Examples.
  4. Where can you use these ideas in practice?

Note: I'm using C# to show code examples. However, these design patterns are part of the Object-oriented design process and can adapt to many OO languages.

1. What is the Fluent Interface Design Pattern?

Fluent Interface Design Pattern is an Object-oriented design process that aims to improve code legibility by cleaning code structure and syntax when creating and manipulating objects without requiring re-specification of the object name each time. Fluent Interface relies extensively on Method Chaining to apply multiple properties to an object.

In C# Linq is one of the most common scenarios where you come across the power of Fluent Interface code allowing the developers to build queries or a variety of complexities and configuration using "standard query operators".

var numbers = new Dictionary<int, string>
{
    { 1, "One" },
    { 2, "Two" },
    { 3, "Three" },
    { 4, "Four" }
};

// Gets all numbers where the Key is 3 or less.
// Then orders the Key in descending order.
// Finally selects all the found dictionary Value's
IEnumerable<string> threeOrLess = numbers
	.Where(t => t.Key <= 3))
	.OrderByDescending(t => t.Key)
	.Select(t => t.Value); // ["Three", "Two", "One"]

// Or if we didn't have Fluent Interface and built the same query progressively.
var threeOrLess = numbers.Where(t => t.Key <= 3);
var sorted = threeOrLess.OrderByDescending(t => t.Key);
var result = sorted.Select(t => t.Value);

2. What is Method Chaining in C#?

Method Chaining is the practice of having one object which can contain multiple methods, which concretely returns the object to which it is attached. In most languages, this is normally referred to as this or self. Each can implement a new property (or method) which gives the stakeholders of the object great control on which properties they assign values to or what side effects to apply.

3. Implementing Fluent Interface and Method Chaining with Examples

Fluent Interface and Method Chaining go hand-to-hand with each other to implement clear, clean code. In the following example we enhance a model class like StudentModel and provide a set of method chains which enables us to decorate with the fluent interface:

// Define the Model
class EmployeeModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string JobTitle { get; set; }
    public decimal Salary { get; set; }
}

// Note you could alternatively use inheritance to contain the `EmployeeModel` like:
// class Employee : EmployeeModel

// But you will have to implement methods using different naming conventions like:
// AddFirstName as FirstName is a public property on EmployeeModel and will be inherited.
// This way of implementing can be very clean as well so you can implement depending on your use case.
// An example I find myself doing alot would be for Test Seeders.

class Employee
{
    private readonly EmployeeModel _employeeModel = new EmployeeModel(); 

    public Employee FirstName(string firstName)
    {
        _employeeModel.FirstName = firstName;
        return this;
    }

    public Employee LastName(string lastName)
    {
        _employeeModel.LastName = lastName;
        return this;
    }

    public Employee JobTitle(string jobTitle)
    {
        _employeeModel.JobTitle = jobTitle;
        return this;
    }

    public Employee Salary(decimal salary)
    {
        _employeeModel.Salary = salary;
        return this;
    }

    // We can also implement methods that don't act as Setters/Getters.
    // For example we want an easy way to print an Employee,
    // Or give an Employee a raise.

    public Employee GiveRaise(decimal salaryIncrease)
    {
        _employeeModel.Salary += salaryIncrease;
        return this;
    }

    public Employee Print()
    {
        Console.WriteLine($"First name: {_employeeModel.FirstName}");
        Console.WriteLine($"Last name: {_employeeModel.LastName}");
        Console.WriteLine($"Job title: {_employeeModel.JobTitle}");
        Console.WriteLine($"Salary: {_employeeModel.Salary}");

        return this;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Using method chaining to create, assign and print. 
        var employee = new Employee()
            .FirstName("John")
            .LastName("Smith")
            .JobTitle("Software Developer")
            .Salary(100000)
            .Print();

        var deservesRaise = new Random().Next(0, 2);
        if (deservesRaise == 1)
        {
            // Using method chaining gives the employee a raise and prints.
            employee.GiveRaise(10000).Print();
        }
    }
}

4. Where can you use these ideas in practice?

I find creating Method Chaining classes a great way to simplify the codebase useful all over my code solutions as it helps split up the business logic while making objects very easy to manipulate for different scenarios. Some of the common scenarios I have used Method Chaining to support fluent assertions are:

  • In Test Seeders to support Unit Tests. Creating a seeder class of a model that I need to mock allows for very customisable data creation depending on the test scenario needed.
  • In Composite pattern classes where we want to build up different properties/functionalities in different scenarios.
  • When creating helper methods to generate and build communications in various whys. For example building emails.
  • When implementing custom log helpers to support various levels of logging.
  • When creating custom HTTP helpers to support advanced APIs and build up different HTTP queries which require complex headers, authentication, body, parameters etc...
  • Building custom Middleware that adds shared functionality to various controllers.
  • Building custom Role and Policy authorisation to manage different levels of authorisation/permission to various parts of web applications.

And many more applications. These were just a few from the long list where I can specifically remember developing some form of Method Chaining. Fluent Interface is pretty baked into C# where you will find yourself using it daily to configure your projects such as adding DI, configuration variables, supporting different middleware, and of course Linq.


Comments

Be the first to comment!