Tuesday, August 2, 2011

Fluent Interface Implementation in C#

Martin Fowler is the first person who mentioned about Fluent Interface term at the end of 2005. It's an implementation of an object oriented API which helps developers provide readable and concise code. At first sight, it looks like method chain technique. But it entails more than just method chaining.

Rhino Mocks is the best example of using Fluent Interface before LINQ in .NET environment. Actually it's really easy to implement this technique by using C#. Please look at the Car Example written below.

Code Example :
In this example I used Car class derived from ICar interface.

   1:  public interface ICar
   2:  {
   3:      ICar SetColor(string color);
   4:      ICar SetEngineType(string engineType);
   5:      ICar StartUp();
   6:      ICar DriveTo(string direction);
   7:      ICar SetSpeed(int speed);
   8:      ICar PullOver();
   9:  }
  10:   
  11:  public sealed class Car : ICar
  12:  {
  13:      private string color;
  14:      private string engineType;
  15:   
  16:      private Car() {}
  17:   
  18:      public static ICar New()
  19:      {
  20:          return new Car();
  21:      }
  22:   
  23:      public ICar SetColor(string color) 
  24:      {
  25:          this.color = color;
  26:          return this;
  27:      }
  28:   
  29:      public ICar SetEngineType(string engineType)
  30:      {
  31:          this.engineType = engineType;
  32:          return this;
  33:      }
  34:   
  35:      public ICar StartUp() 
  36:      {
  37:          Console.WriteLine("Started Up");
  38:          return this;
  39:      }
  40:   
  41:      public ICar DriveTo(string direction) 
  42:      {
  43:          Console.WriteLine("Driving to " + direction);
  44:          return this;
  45:      }
  46:   
  47:      public ICar SetSpeed(int speed) 
  48:      {
  49:          Console.WriteLine(speed + "km per hour") ;
  50:          return this;
  51:      }
  52:   
  53:      public ICar PullOver() 
  54:      {
  55:          Console.WriteLine("Pulled over");
  56:          return this;
  57:      }
  58:  }

At Line 16, I used private constructor in order to prevent instantiate Car class.
At Line 18, New() method is used and marked as static
At Line 20, I created a new instance of Car class.

As you see all methods in Car class return ICar interface to provide chain reaction.

Using Car class in Main Method

   1:  static void Main(string[] args)
   2:  {
   3:      ICar car = Car.New()
   4:          .SetColor("Red")
   5:          .SetEngineType("Diesel")
   6:          .StartUp()
   7:          .DriveTo("north")
   8:          .SetSpeed(120)
   9:          .PullOver();
  10:   
  11:      Console.Read();
  12:  }

At line 3; I'm able to set all properties and call methods in one statement. It's fairly easy to design, read and brief.

The disadvantage of this technique is difficult to debug. Because in Visual Studio it's not easy to put break point for each method calling.

2. Code Example : ConnectionString
The following code example is much more realistic than the example above. In this code snippet contains IConnectionString interface and ConnectionString class inherits from IConnectionString

   1:  public interface IConnectionString
   2:  {
   3:      IConnectionString SetServer(string server);
   4:      IConnectionString SetDatabase(string database);
   5:      IConnectionString SetUsername(string username);
   6:      IConnectionString SetPassword(string password);
   7:  }
   8:  public class ConnectionString : IConnectionString
   9:  {
  10:      private string Server;
  11:      private string Database;
  12:      private string Username;
  13:      private string Password;
  14:   
  15:      public override string ToString()
  16:      {
  17:          return string.Format(@"Data Source={0};Initial Catalog={1};User Id={2};Password={3};", 
  18:              Server, Database, Username, Password); 
  19:      }
  20:   
  21:      private ConnectionString() { }
  22:      public static IConnectionString New() 
  23:      {
  24:          return  new ConnectionString();
  25:      }
  26:   
  27:      public IConnectionString SetServer(string server)
  28:      {
  29:          this.Server = server;
  30:          return this;
  31:      }
  32:   
  33:      public IConnectionString SetDatabase(string database)
  34:      {
  35:          this.Database = database;
  36:          return this;
  37:      }
  38:   
  39:      public IConnectionString SetUsername(string username)
  40:      {
  41:          this.Username = username;
  42:          return this;
  43:      }
  44:   
  45:      public IConnectionString SetPassword(string password)
  46:      {
  47:          this.Password = password;
  48:          return this;
  49:      }
  50:  }

Using ConnectionString :

   1:  static void Main(string[] args)
   2:  {
   3:      IConnectionString connectionString = ConnectionString.New()
   4:          .SetServer("127.0.0.1")
   5:          .SetDatabase("AdventureWorks")
   6:          .SetUsername("WebUser")
   7:          .SetPassword("123456");
   8:   
   9:      Console.WriteLine(connectionString.ToString());
  10:   
  11:      Console.Read();
  12:  }

Output :
Data Source=127.0.0.1;Initial Catalog=AdventureWorks;User Id=WebUser;Password=12
3456;

More information for Fluent Interface :
http://randypatterson.com/index.php/2007/09/26/how-to-design-a-fluent-interface/
http://www.hanselman.com/blog/TheWeeklySourceCode14FluentInterfaceEdition.aspx
http://www.bofh.org.uk/2005/12/21/fluent-interfaces

0 comments: