Hi I would like to build a fluent interface for creating am object some sort of factory or builder.
I understand that I have to "return this" in order to make the methods chainable.
public class CarBuilder
{
public CarBuilder()
{
car = new Car();
}
private Car car;
public CarBuilder AddEngine(IEngineBuilder engine)
{
car.Engine = engine.Engine();
return this;
}
public CarBuilder AddWheels(IWheelsBuilder wheels)
{
car.Wheels = wheels.Wheels();
return this;
}
public CarBuilder AddFrame(IFrameBuilder frame)
{
car.Frame = frame.Frame();
return this;
}
public Car BuildCar()
{
return car;
}
}
with this I could build a car like that:
Car c = builder.AddFrame(fBuilder).AddWheels(wBuilder).AddEngine(eBuilder).BuildCar();
But what I need is a special sequence or workflow: I can only build the wheels on top of the frame and when the wheels exist then I'll be able to build up the engine. So instead of offering every method of the car builder I want to be able to add only the frame to the builder and then only the wheels to the frame and then the engine on top of that...
And how would it be or what would be a good implementation if the EngineBuilder itself has a fluent api like eBuilder.Cylinders(12).WithPistons()....
Would it be possible to have something like this
Car c = builder.AddFrame(fBuilder).AddWheels(wBuilder).AddEngine(x=>x.WithCylinders(12).WithPistons()).BuildCar();
So in sum how to structure the flow of the fluent interface and how to nest fluent Interfaces?
Instead of having a single CarBuilder class that exposes all the methods, you have multiple classes that each expose only the methods appropriate for the "state" of the car being built.
Given your example, CarBuilder
would offer only AddFrame
. Instead of returning this
, AddFrame
returns an object of class CarBuilderWithFrame
that offers only AddWheels
, which returns an object of class CarBuilderWithFrameAndWheels
that offers only AddEngine
, which returns an object of class CarBuilderWithEverything
that offers only Build
.
This example is very serial, and you can argue over whether it makes sense to go through this much work for such a linear process.
An example I like is for printing. A Printer object could return a PrintJob object that offers three methods: Cancel, Print, or StartPage. The StartPage method would return a Page object that gives you methods for all the drawing commands one one called EndPage that gives you the PrintJob object back. This makes it easy to hardcode a simple print job.
Printer.StartPrintJob().StartPage().DrawText("Title").DrawIcon("logo.png").EndPage().Print();