Hi i'm trying to understand how i could build a readable and also error preventing Fluent-API without to much restriction for the User
to hold it simple let's say we want to change the following class to be fluent
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 void WithHorsePower(int bhp)
{
Bhp = bhp;
return this;
}
public void WithFuel(int gallons)
{
Gallons = gallons;
}
public void WithWeight(int tons)
{
Tons = tons;
}
public int Mpg()
{
return Gallons/Tons;
}
}
the problem in this case the user should only be able to access Mpg()
if Weight()
and Fuel()
got called first also the position of HorsePower()
is irrelevant.
Samples:
int mpg =Car.Create().HorsePower().Fuel().Weight().Mpg();
int mpg =Car.Create().Fuel().HorsePower().Weight().Mpg();
int mpg =Car.Create().HorsePower().Fuel().HorsePower().Weight().Mpg();// <- no typo
int mpg =Car.Create().Fuel().Weight().HorsePower().Mpg();
int mpg =Car.Create().Weight().HorsePower().Fuel().Mpg();
int mpg =Car.Create().Weight().Fuel().Mpg();
Is there a easy way to do this without a big bunch of interfaces?
I also doesn't how to implement this nested interfaces in the right way
Here are the interfaces i currently created
interface Start
{
IFuelWeight1 HorsePower();
IHorsePowerWeight1 Fuel();
IHorsePowerFuel1 Weight();
}
interface IFuelWeight1 // Start.HorsePower()
{
IHorsePowerWeight1 Fuel();
IHorsePowerFuel1 Weight();
}
interface IHorsePowerWeight1 // Start.Fuel()
{
IHorsePowerWeight1 HorsePower();
IHorsePowerFuelMpg Weight();
}
interface IHorsePowerFuel1 // Start.Weight()
{
IHorsePowerFuel1 HorsePower();
IHorsePowerWeightMpg Fuel();
}
#region End
interface IHorsePowerFuelMpg
{
IFuelWeightMpg HorsePower();
IHorsePowerWeightMpg Fuel();
int Mpg();
}
interface IHorsePowerWeightMpg
{
IFuelWeightMpg HorsePower();
IHorsePowerFuelMpg Weight();
int Mpg();
}
interface IFuelWeightMpg
{
IHorsePowerWeightMpg Fuel();
IHorsePowerFuelMpg Weight();
int Mpg();
}
#endregion
EDIT for Adam Houldsworth :-)
How to Implement the interface above to do this?:
var k = myMiracle as Start;
k.Fuel().Weight();
k.Weight().Fuel();
k.HorsePower().Fuel().Weight();
k.HorsePower().Weight().Fuel();
k.Fuel().HorsePower().Weight();
k.Weight().HorsePower().Fuel();
One alternative could be to invoke all operations on Mpg() which will allow the other operations to be conditional.
This is already answered in SO with a code sample. Please refer to Conditional Builder Method Chaining Fluent Interface
The post indicates, instead of Interfaces, the same might be achieved using constructors, with a calling method that makes all others operations conditional.