This is a tutorial article that starts with an introduction to Fluent Interface Pattern in C#. This is followed by a discussion of Hierarchical Fluent Interface. Finally, quite a complicated inheritance problem with Fluent Interface Pattern is discussed. The intended audience is intermediate level C# programmers and above.
Fluent Interface Pattern – Introduction
Fluent Interface Pattern is a design guideline for OO languages that advices that exposed API, that is class public
methods should, in order to increase readability, try to “appear” as a domain-specific language (DSL). Main tool to create DSL is advised to be “method chaining”. We want to have interface (API) like this:
Employee empl = new Employee();
empl.SetFirstName("John").SetLastName("Smith").SetAge(30).Print();
Method chaining is in C#, like in many OO languages, achieved by returning object itself, that is “this
” object, as a method result. That enables next method to be chained to previous method return value. On abstract level, we are really returning a domain context to a subsequent method in method chaining. Method chaining is terminated with method that returns a void
context.
Fluent Interface Pattern is just concerned about how interface should look like, it does not prescribe pattern in classical sense how to achieve it. As long as you have interface in form of method chaining, that “looks like” natural language and is therefore considered to be “user friendly”, it considers that you created your own form of “domain-specific language (DSL)” and is happy all about it.
Classic approach-Setters-Example Code
Here is a classic code example using standard setters. This kind of programming is widely advised in OO and C# literature.
public class Employee
{
private string FirstName = null;
private string LastName = null;
private int Age = 0;
public void SetFirstName(string fName)
{
FirstName = fName;
}
public void SetLastName(string lName)
{
LastName = lName;
}
public void SetAge(int age)
{
Age = age;
}
public void Print()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}",
FirstName, LastName, Age);
Console.WriteLine(tmp);
}
}
class Client
{
static void Main(string[] args)
{
Employee empl = new Employee();
empl.SetFirstName("John");
empl.SetLastName("Smith");
empl.SetAge(30);
empl.Print();
Console.ReadLine();
}
}
And here is the execution result:
FirstName:John; LastName:Smith; Age:30
Fluent Interface -Method Chaining - Example Code
Here is the code example with method chaining. This is basically the same class as in the above example, that follows recommendations of Fluent Interface Pattern. The main trick applied here is to return “this
” object so methods can be chained.
public class Employee
{
private string FirstName = null;
private string LastName = null;
private int Age = 0;
public Employee SetFirstName(string fName)
{
FirstName = fName;
return this;
}
public Employee SetLastName(string lName)
{
LastName = lName;
return this;
}
public Employee SetAge(int age)
{
Age = age;
return this;
}
public void Print()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}",
FirstName, LastName, Age);
Console.WriteLine(tmp);
}
}
class Client
{
static void Main(string[] args)
{
Employee empl = new Employee();
empl.SetFirstName("John").SetLastName("Smith").SetAge(30).Print();
Console.ReadLine();
}
}
And here is the execution result:
FirstName:John; LastName:Smith; Age:30
Fluent Interface -Method Chaining using Extensions-Example Code
Of course, we can use Extension methods in C# to achieve the same result as above. Please note that we needed to change access level of attributes of Employee
to public
, so extension methods can use them.
public class Employee
{
public string FirstName = null;
public string LastName = null;
public int Age = 0;
}
public static class EmployeeExtensions
{
public static Employee SetFirstName(this Employee emp, string fName)
{
emp.FirstName = fName;
return emp;
}
public static Employee SetLastName(this Employee emp, string lName)
{
emp.LastName = lName;
return emp;
}
public static Employee SetAge(this Employee emp, int age)
{
emp.Age = age;
return emp;
}
public static void Print(this Employee emp)
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}",
emp.FirstName, emp.LastName, emp.Age);
Console.WriteLine(tmp);
}
}
class Client
{
static void Main(string[] args)
{
Employee empl = new Employee();
empl.SetFirstName("John").SetLastName("Smith").SetAge(30).Print();
Console.ReadLine();
}
}
And here is the execution result:
FirstName:John; LastName:Smith; Age:30
Hierarchical Fluent Interface
As mentioned before, Fluent Interface pattern leaves to programmer and his judgement to decide how exactly his specific version of “domain-specific language (DSL)” is going to look like. The programmer is free to choose method names and organization of method chaining that to him looks the most “user friendly” and alike natural language.
One typical use case is creating of Hierarchical Fluent Interface. In such a case, programmer decides to group properties into hierarchical groups and in that way, expose it to the library/class user. For example, programmer might decide to divide Employee
data into two groups:
PersonalData
; and EmploymentData
That would result in an interface like this:
Employee empl = new Employee();
empl.Fluent
.PersonalData
.FirstName("John").LastName("Smith").Age(30)
.EmploymentData
.Company("CNN").Position("Host").Salary(50000);
We will provide here sample project of how to create such an interface. It is not necessarily the pattern programmer should follow to achieve Hierarchical Fluent Interface. The programmer is free to choose his own implementation technique if he desires. However, this gives a good and reusable example code. We will not be going into design/implementation details of this project, since most is self-explanatory.
Here is the class diagram:
And here is the code for Hierarchical Fluent Interface:
public class Employee
{
public string FirstName = null;
public string LastName = null;
public int Age = 0;
public string Company = null;
public string Position = null;
public int Salary = 0;
public FluentEmployee Fluent
{
get { return new FluentEmployee(this); }
}
public override string ToString()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}
\nCompany:{3}; Position:{4}; Salary:{5}",
this.FirstName, this.LastName, this.Age, this.Company,
this.Position, this.Salary);
return tmp;
}
}
public class FluentEmployee
{
protected Employee _employee = null;
public FluentEmployee()
{
_employee = new Employee();
}
public FluentEmployee(Employee emp)
{
_employee = emp;
}
public FluentEmployeePersonalData PersonalData
{
get { return new FluentEmployeePersonalData(_employee); }
}
public FluentEmployeeEmploymentData EmploymentData
{
get { return new FluentEmployeeEmploymentData(_employee); }
}
}
public class FluentEmployeeEmploymentData : FluentEmployee
{
public FluentEmployeeEmploymentData(Employee emp)
: base(emp)
{
}
public FluentEmployeeEmploymentData Company(string comp)
{
_employee.Company = comp;
return this;
}
public FluentEmployeeEmploymentData Position(string pos)
{
_employee.Position = pos;
return this;
}
public FluentEmployeeEmploymentData Salary(int sal)
{
_employee.Salary = sal;
return this;
}
}
public class FluentEmployeePersonalData : FluentEmployee
{
public FluentEmployeePersonalData(Employee emp)
: base(emp)
{
}
public FluentEmployeePersonalData FirstName(string fName)
{
_employee.FirstName = fName;
return this;
}
public FluentEmployeePersonalData LastName(string lName)
{
_employee.LastName = lName;
return this;
}
public FluentEmployeePersonalData Age(int age)
{
_employee.Age = age;
return this;
}
}
class Client
{
static void Main(string[] args)
{
Employee empl = new Employee();
empl.Fluent
.PersonalData
.FirstName("John").LastName("Smith").Age(30)
.EmploymentData
.Company("CNN").Position("Host").Salary(50000);
Console.WriteLine(empl.ToString());
Console.ReadLine();
}
}
Here is the result of execution:
FirstName:John; LastName:Smith; Age:30
Company:CNN; Position:Host; Salary:50000
Inheriting Fluent Interface Classes
The problem arises when we want to inherit class that implements Fluent Interface. Let us assume we have class Employee
and class Manager
that inherits from it. Let it be like on this class diagram:
And here is the code:
public class Employee
{
protected string FirstName = null;
protected string LastName = null;
protected int Age = 0;
public Employee SetFirstName(string fName)
{
FirstName = fName;
return this;
}
public Employee SetLastName(string lName)
{
LastName = lName;
return this;
}
public Employee SetAge(int age)
{
Age = age;
return this;
}
public override string ToString()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}",
FirstName, LastName, Age);
return tmp;
}
}
public class Manager : Employee
{
protected int Bonus = 0;
public Manager SetBonus(int bonus)
{
Bonus = bonus;
return this;
}
public override string ToString()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}; Bonus:{3}",
FirstName, LastName, Age, Bonus);
return tmp;
}
}
What we would like to have is interface like this:
Manager mgr = new Manager();
mgr.SetFirstName("John").SetLastName("Smith")
.SetAge(30).SetBonus(1000);
But this will not compile. The reason is that we now have two types of “this
” object returned, of type Employee
and of type Manager
. Once we get back base class object “this
” as Employee
, methods of class Manager
are not available any more.
So, method Employee.SetAge()
would return object of type Employee
and there is no way to method-chain methods from class Manager
.
So, is there a way to trick method Employee.SetAge()
to return object of type subclass Manager
? We need that to be able to do our Fluent Interface, that is Method-Chaining?
Answer is yes, it is possible, but technically complicated. It involves usage of “Recursive Generics”. I am going to show a working code example here.
I am not going to explain in detail how the solution works. If you can read C# Generics code, you will be able to understand this quite advanced design.
Key problem that needs to be solved in this solution is how to communicate return class type from derived class to base class. Key trick is to always return in Fluent Interface object of original (derived) class. That is resolved using Generics and type parameter SELF. Follow SELF from most derived class (like CEO, Manager, Employee) down the inheritance hierarchy and you will understand how this code works. Where clause ( like “where SELF : EmployeeFluent<SELF>”) is there just to ensure that class is used as part of inheritance hierarchy.
Here is the class diagram of this solution for Inheriting Fluent Interface classes.
Here is the code of this solution for Inheriting Fluent Interface classes.
public class EmployeeFluent<SELF>
where SELF : EmployeeFluent<SELF>
{
protected string FirstName = null;
protected string LastName = null;
protected int Age = 0;
public SELF SetFirstName(string fName)
{
FirstName = fName;
return (SELF)this;
}
public SELF SetLastName(string lName)
{
LastName = lName;
return (SELF)this;
}
public SELF SetAge(int age)
{
Age = age;
return (SELF)this;
}
public override string ToString()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}",
FirstName, LastName, Age);
return tmp;
}
}
public class Employee : EmployeeFluent<Employee> { };
public class ManagerFluent<SELF> : EmployeeFluent<SELF>
where SELF : ManagerFluent<SELF>
{
protected int Bonus = 0;
public SELF SetBonus(int bonus)
{
Bonus = bonus;
return (SELF)this;
}
public override string ToString()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}; Bonus:{3}",
FirstName, LastName, Age, Bonus);
return tmp;
}
}
public class Manager : ManagerFluent<Manager> { };
public class CEOFluent<SELF> : ManagerFluent<SELF>
where SELF : CEOFluent<SELF>
{
protected int CompanyShares = 0;
public SELF SetCompanyShares(int shares)
{
CompanyShares = shares;
return (SELF)this;
}
public override string ToString()
{
string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}; Bonus:{3};
CompanyShares:{4}",
FirstName, LastName, Age, Bonus, CompanyShares);
return tmp;
}
}
public class CEO : CEOFluent<CEO> { };
class Client
{
static void Main(string[] args)
{
CEO ceo1 = new CEO();
ceo1.SetFirstName("John").SetLastName("Smith")
.SetAge(30).SetBonus(1000).SetCompanyShares(5000);
Manager mgr = new Manager();
mgr.SetFirstName("Cedomir").SetLastName("Jokic")
.SetAge(40).SetBonus(2000);
Employee emp = new Employee();
emp.SetFirstName("Novak").SetLastName("Djokovic")
.SetAge(20);
Console.WriteLine(ceo1.ToString());
Console.WriteLine(mgr.ToString());
Console.WriteLine(emp.ToString());
Console.ReadLine();
}
}
Here is the sample execution of this solution for Inheriting Fluent Interface classes.
Conclusion
Fluent Interface Pattern has gained a lot of popularity and is here to stay. Just to mention LINQ where it is extensively used.
History
- 2nd March, 2022: Initial version
Mark Pelf is the pen name of just another Software Engineer from Belgrade, Serbia.
My Blog https://markpelf.com/