When using method chaining like:
var car = new Car().OfBrand(Brand.Ford).OfModel(12345).PaintedIn(Color.Silver).Create();
there may be two approaches:
-
Reuse the same object, like this:
public Car PaintedIn(Color color) { this.Color = color; return this; }
-
Create a new object of type
Car
at every step, like this:public Car PaintedIn(Color color) { var car = new Car(this); // Clone the current object. car.Color = color; // Assign the values to the clone, not the original object. return car; }
Is the first one wrong or it's rather a personal choice of the developer?
I believe that he first approach may quickly cause the intuitive/misleading code. Example:
// Create a car with neither color, nor model.
var mercedes = new Car().OfBrand(Brand.MercedesBenz).PaintedIn(NeutralColor);
// Create several cars based on the neutral car.
var yellowCar = mercedes.PaintedIn(Color.Yellow).Create();
var specificModel = mercedes.OfModel(99).Create();
// Would `specificModel` car be yellow or of neutral color? How would you guess that if
// `yellowCar` were in a separate method called somewhere else in code?
Any thoughts?
Best Answer
I'd put the fluent api to it's own "builder" class seperate from the object it is creating. That way, if the client doesn't want to use the fluent api you can still use it manually and it doesn't pollute the domain object (adhering to single responsibility principle). In this case the following would be created:
Car
which is the domain objectCarBuilder
which holds the fluent APIThe usage would be like this:
The
CarBuilder
class would look like this (I'm using C# naming convention here):Note that this class will not be thread safe (each thread will need it's own CarBuilder instance). Also note that, even though fluent api is a really cool concept, it probably is overkill for the purpose of creating simple domain objects.
This deal is more useful if you're creating an API for something much more abstract and has more complex set up and execution, which is why it works great in unit testing and DI frameworks. You can see some other examples under the Java section of the wikipedia Fluent Interface article with persistance, date handling and mock objects.
EDIT:
As noted from the comments; you could make the Builder class a static inner class (inside Car) and Car could be made immutable. This example of letting Car be immutable seems a bit silly; but in a more complex system, where you absolutely don't want to change the contents of the object that is built, you might want to do it.
Below is one example of how to do both the static inner class and how to handle an immutable object creation that it builts:
The usage would be the following:
Edit 2: Pete in the comments made a blog post about using builders with lambda functions in the context of writing unit tests with complex domain objects. It is an interesting alternative to make the builder a bit more expressive.
In the case of
CarBuilder
you need to have this method instead:Which can be used as this: