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!