Acase().for(patternType.FluentInterfaces).create()

When I was first exposed to the idea of fluent interfaces my response was… big flipping deal.

It wasn’t until I actively started using fluent interfaces in my code did I begin to see their power and elegance.

What is a fluent interface? Here is the obligatory link to wikipedia 😉

In simple terms, its returning a type instead of void in order to achieve method chaining.

The end goal of the method chaining is to provide a more readable interface and code.

First, does it break the Law of Demeter?

Law of Demeter doesn’t equal the number of periods. I am of the opinion fluent interfaces do not violate the Law of Demeter.

What is LoD? Another link to wiki and here is a link to a stack overflow on this very subject! 🙂

To me, Law of Demeter is about restricting communication between objects.

A common violation of LoD (imho) is the exposure of a list property on an object. I believe this serves as a good example of LoD as well as being an example on how to make a fluent interface. 🙂

A Person object has a name and a list of friends.

   1:      public class Person
   2:      {
   3:          public string Name { get; set; }
   4:          public List<Person> Friends { get; set; }
   5:   
   6:          public Person()
   7:          {
   8:              Friends = new List<Person>();
   9:          }
  10:      }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }


I could then add friends by…

 
   1:  var roger = new Person{ Name="Roger" };
   2:  roger.Friends.Add(new Person { Name = "Eddie" });
   3:  roger.Friends.Add(new Person { Name = "Freddie" });
   4:  roger.Friends.Add(new Person { Name = "Gordie" });

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Now this is pretty typical, so what’s the problem?

Well my code knows WAY too much about Person. I know it has a list of friends and if they change that list to say a dictionary, I am hosed.

Not only that, but poor Person class… people can add friends to his collection without him every knowing. What if some additional logic needs to be done when adding a friend?

What if the person wants to record the birth date of every friend so they can send out birthday cards? Person is SOL.

As for Law of Demeter, my code is using the Person object to communicate through to the List<Person>. I am exposing my code to changes in Person.

Let’s change Person to eliminate this problem.

   1:      public class Person2
   2:      {
   3:          public string Name { get; set; }
   4:          private readonly List<Person2> _friends;
   5:   
   6:          public Person2()
   7:          {
   8:              _friends = new List<Person2>();
   9:          }
  10:   
  11:          public void AddFriend(Person2 friend)
  12:          {
  13:              _friends.Add(friend);
  14:          }
  15:      }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Now the only way to add a friend is through Person. Yippie!

 

   1:  var roger2 = new Person2 {Name = "Roger"};
   2:  roger2.AddFriend(new Person2 { Name = "Eddie" });
   3:  roger2.AddFriend(new Person2 { Name = "Freddie" });
   4:  roger2.AddFriend(new Person2 { Name = "Gordie" });

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

If I wanted to make this a fluent interface all I would need to do is instead of returning void, return the Person class.

   1:      public class Person3
   2:      {
   3:          public string Name { get; set; }
   4:          private readonly List<Person3> _friends;
   5:   
   6:          public Person3()
   7:          {
   8:              _friends = new List<Person3>();
   9:          }
  10:   
  11:          public Person3 AddFriend(Person3 friend)
  12:          {
  13:              _friends.Add(friend);
  14:              return this;
  15:          }
  16:      }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Now I can do the same logic like…

   1:  var roger3 = new Person3 { Name = "Roger" }
   2:                              .AddFriend(new Person3 { Name = "Eddie" })
   3:                              .AddFriend(new Person3 { Name = "Freddie" })
   4:                              .AddFriend(new Person3 { Name = "Gordie" });

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

That is pretty cool, but fluent interfaces really shine with the builder pattern.

This time around I want to force construction of a person through a builder and have the builder use a fluent interface. Notice my Person’s constructor and fields are private. I embed the builder class within the Person class so the builder has access to the constructor and fields. In this manner only my builder class has access to constructing a person. My builder can now act as an anti-corruption layer for Person.

   1:      public class Person4
   2:      {
   3:          private string _name;
   4:          private List<Person4> _friends;
   5:   
   6:          private Person4()
   7:          {
   8:              _friends = new List<Person4>();
   9:          }
  10:   
  11:          public Person4 AddFriend(Person4 friend)
  12:          {
  13:              _friends.Add(friend);
  14:              return this;
  15:          }
  16:   
  17:          public static PersonBuilder createAPerson()
  18:          {
  19:              return new PersonBuilder();
  20:          }
  21:   
  22:          public class PersonBuilder
  23:          {
  24:              private Person4 _person;
  25:              public PersonBuilder()
  26:              {
  27:                  _person = new Person4();
  28:              }
  29:   
  30:              public PersonBuilder named(string name)
  31:              {
  32:                  _person._name = name;
  33:                  return this;
  34:              }
  35:   
  36:              public PersonBuilder withFriend(Person4 friend)
  37:              {
  38:                  _person.AddFriend(friend);
  39:                  return this;
  40:              }
  41:   
  42:              public PersonBuilder withaFriendNamed(string name)
  43:              {
  44:                  var friend = createAPerson().named(name).finish();
  45:                  _person.AddFriend(friend);
  46:                  return this;
  47:              }
  48:   
  49:              public Person4 finish()
  50:              {
  51:                  return _person;
  52:              }
  53:          }
  54:      }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Now to create Roger and his friends I do..

 
   1:  var roger4 = Person4.createAPerson()
   2:                      .named("Roger")
   3:                      .withaFriendNamed("Eddie")
   4:                      .withaFriendNamed("Freddie")
   5:                      .withaFriendNamed("Gordie")
   6:                      .finish();       

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

It’s a simple example but maybe it sparked some ideas on how to use fluent interfaces to chain methods and make your code more approachable to people without Computer Science degrees. 😀

JB

Advertisements