Chưa phân loại

C# Tutorial – Creating a C# Fluent API

Introduction

Fluent interfaces are a fun and discoverable way to allow fellow developers to access functionality. If you’ve ever used Linq’s dot(.) notation, then you’ve used a fluent interface. Not only are fluent interfaces easy to use, but with the right knowledge they are also easy to create.

If you don’t know what a fluent interface is, then let me show you through a simple example. This example allows you to calculate the miles per gallon for a vehicle given a few required values:

var mpg = new Car(make : "audi", model: "a4")
             .WithHorsePower(250)
             .WithFuel(gallons:10)
             .WithWeight(tons:3)
             .Mpg();

Compare the fluent approach with the traditional C# get/set pattern.

var car = new Car(make: "audi", model: "a4") {
    HorsePower = 250,
    Fuel = 10,
    Weight = 3
}

var mpg = car.Mpg();

Both approaches to this particular problem are perfectly fine. So why would you use a fluent interface over the traditional method?

In my humble opinion, I find that (good) fluent interfaces help dictate direction, and keep you from missing a crucial step in your setup. In the traditional approach what would stop us from calling the Mpg method before setting any of the other properties? The answer is nothing, and that can leave your developer in a state of confusion as to why their result is incorrect or throwing exceptions.

I also believe that fluent interfaces do a better job of encapsulation. It would be very difficult for another developer or part of your application to modify values accidentally. This would be possible in the traditional approach, and not possible with the fluent interface.

if (car.Fuel = 30) // doh!

So let’s break down our example and see what parts are important to a fluent interface.

Entry Point

 new Car(make : "audi", model:"a4") // entry point

Every fluent interface needs an entry point. A place where the developer must start in order to begin the chaining process. In our example, the entry point is just a simple constructor, but does not have to be: It could be a static method, a method, or property.

Chaining Methods

.WithHorsePower(250)
.WithFuel(gallons:10)
.WithWeight(tons:3)

Once you get passed the entry point, you are left with all the chaining methods. Chaining methods are capable of many things, but they are usually allow you to set properties. Nothing mind blowing here, but these methods are critical to setting the state you need for the executor.

Executor(s)

.Mpg(); // the executor

The executor is arguably the most important part of the fluent interface. It allows you to escape the chaining methods and finally return a result. Think of the executor method as the period on the end of a sentence. You are also not limited to one executor, you may have as many as makes sense to your API.

Now that I’ve broken down the different parts of the fluent interface, let’s build it!

Show Me The Code!

How do we get to the interface we have above? let’s start by knowing we need a Car class.

public class Car
{
    private readonly string _make;
    private readonly string _model;

    public Car(string make, string model)
    {
        _make = make;
        _model = model;
    }
}

So this helps us define the entry point. Our entry point in this case is the Car constructor. The next step is to build the chaining methods.

public class Car
{
    private readonly string _make;
    private readonly string _model;
    private int _bhp;
    private int _gallons;
    private int _tons;

    public Car(string make, string model)
    {
        _make = make;
        _model = model;
    }

    public Car WithHorsePower(int bhp)
    {
        _bhp = bhp;
        return this;
    }

    public Car WithFuel(int gallons)
    {
        _gallons = gallons;
        return this;
    }

    public Car WithWeight(int tons)
    {
        _tons = tons;
        return this;
    }
}

Here is the real magic. I am returning the Car itself after every method call. This allows you to chain to the next method. In this example, I am not constraining what methods you might want to call next, or the fact that you have to call any of them. If you want to constrain what the next call is, you can return another class / interface with one method (the next method). Note, calling the same method multiple times will just override the old value.

Finally, let’s implement the executor. I’ve also taken the liberty to allow developers access to the values through read-only properties.

public class Car
{
    public int Gallons { get; private set; }
    public int Tons { get; private set; }
    public int Bhp { get; private set; }
    public string Make { get; private set; }
    public string Model { get; private set; }

    public Car(string make, string model)
    {
        Make = make;
        Model = model;
    }

    public Car WithHorsePower(int bhp)
    {
        Bhp = bhp;
        return this;
    }

    public Car WithFuel(int gallons)
    {
        Gallons = gallons;
        return this;
    }

    public Car WithWeight(int tons)
    {
        Tons = tons;
        return this;
    }

    public int Mpg()
    {
        // please don't use this for real mpg
        return Gallons/Math.Max(Tons, 1);
    }
}

It is important that the executor return something other than Car or else you will still be stuck in the chaining methods. Also note that readonly properties are also executors; calling any of them will not allow you to chain any more methods. This class is now fluent and ready to be used with the example from the introduction.

Conclusion

This pattern is very powerful and can be expanded once you realize what you need to do to facilitate it. It doesn’t work in every situation but in those times where you would like to give guidance to other developers this approach gives you a great way to bake that guidance directly into your API.

Hope this helps you in better understanding the fluent interface approach and if you have any questions or if I could make anything clearer please don’t hesitate to ask.

Happy coding!!

From tech.pro

Advertisements

1 thought on “C# Tutorial – Creating a C# Fluent API”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s