Beginner - Method Chaining

Exploring the topic of method chaining within OOP, we’ll define a simple contract and enable chaining method/function calls sequentially

I was talking to a recent boot grad who had not covered this within their course syllabus, so let’s jump into an example

Scenario

Jim ๐Ÿง” is making a sandwich, he already knows which ingredients his fridge contains which he’ll be using:

  • Mayonnaise โฌœ
  • Lettuce ๐Ÿƒ
  • Cheese ๐Ÿง€
  • Ham ๐Ÿฅ“

Jim will need to visit the fridge for each ingredient added to the sandwich. Each trip requires a reference to the fridge, and removal of an item

Could Jim, make this sandwich creation operation better?

When we think about this scenario as code, it would be something like:

    var fridge = new Fridge();

    fridge.RemoveMayonnaise();
    fridge.RemoveCheese();
    fridge.RemoveHam();
    fridge.RemoveLettuce();

Figure 1: fridge and removal of items

This pattern of calling multiple methods from an object is something very common in Object-oriented programming. Whilst perfectly valid, this suffers from some issues:

  • We’re re-referencing the object, again and again, typing the word fridge and invoking a method each line
  • We’re creating a lot of noise and lines

Whilst clear in the example above, it lacks any form of relation, with each call being completely independent. Think of this as a series of cogs.

In our code example, the links are placed one after another, but they could become easily separated and it’s hard to keep them in order. Now imagine the links linking together like a… chain! We have a specific order, we can even enforce a certain order but that’s a future topic ๐Ÿ˜‰.

Let’s look at how method chaining can help us here.

If you’ve used anything from the System.Linq namespace, it’s highly likely you’ve used method chaining, an example of this can be found below:

            var people = peoples.Where(p => p.Age >= 30)
                .OrderByDescending(p => p.Name)
                .Take(10)
                .ToList();

Note: the example above uses fluent interfaces too, but we’ll get into that another time.

Some benefits for method chaining are:

  • To form a chain of available commands which are tied to an object
  • Create a sequence of processing ‘steps’ that are optional and require no particular order
  • Simpler and cleaner calling code

Sounds good? Let’s get started.

Improving the code in Figure 1

To create method chaining, there’s two requirements for our code:

  • Each method will need to have a return type of the class we’re using
  • At the end of each method, we’ll need to return the current object instance

Let’s modify the RemoveMayonnaise method with these changes:

     public Fridge RemoveMayonnaise()
     {
         // implementation omitted for brevity
         return this;
     }

Line 1 - Here we’re stating the object type which will be returned Line 3 - Here we’re returning the instance of itself this from the method

Because we’re returning the object Fridge and we’re returning an instance, we can then access any public method within the Fridge instance, welcome to method chaining. Let’s add the remaining methods for illustration below:

   class Program
    {
        static void Main(string[] args)
        {
            // ### Previous code
            // var fridge = new Fridge();

            // fridge.RemoveMayonnaise();
            // fridge.RemoveCheese();
            // fridge.RemoveHam();
            // fridge.RemoveLettuce();

            // ### New code
            var fridge = new Fridge();

            fridge.RemoveMayonnaise()
                .RemoveHam()
                .RemoveCheese()
                .RemoveLettuce();
        }
    }


    class Fridge
    {
        public Fridge RemoveMayonnaise()
        {
            // implementation omitted for brevity
            return this;
        }

        public Fridge RemoveLettuce()
        {
            // implementation omitted for brevity
            return this;
        }

        public Fridge RemoveCheese()
        {
            // implementation omitted for brevity
            return this;
        }

        public Fridge RemoveHam()
        {
            // implementation omitted for brevity
            return this;
        }
    }

Our calling code under the ### New code comment is smaller, more fluid and looks much cleaner in comparison to ### Previous code.

But Wait…

Jim is back ๐Ÿง”, the good news is now thanks to our method chaining, Jim can gather his ingredients in one trip to the fridge.

Now the bad news, from his last sandwich creation, placing the lettuce at the bottom of the bread makes it moist and threatens the structural integrity of the sandwich, therefore we need to use the ingredients in a specific order.

But how can we enforce a sequence of events?

Let’s cover that in the next blog post, fluent interfaces!

Ash Grennan
Ash Grennan
Snr Software Engineer

Deliver value first, empower teams to make technical decisions. Snr Engineer @ Moonpig, hold a BSc & MSc in software engineering & certified AWS Solutions Architect (LinkedIn). A fan of Serverless computing, distributed systems, and anything published by serverless.com ๐Ÿงก