I am trying to understand fluent builder patterns and in my case, I have an object that has child objects too. Most of the online examples are based on a single object. There are some examples for nested objects but they all are different. So I am here to find out what is the correct way to implement a fluent builder pattern for my case.
public class Controller
{
private Robot _robot;
private Table _table;
public Controller() {}
public void Place() {}
public void Action() {}
}
public class Robot
{
private Point _currentLocation;
public Robot(Point point) {}
public void Move(){}
}
public class Table
{
private int _width;
private int _length;
public Table(int width, int length){}
public bool IsValidLocation(Point point){}
}
------------ Edited ----------
I have approached implementing this as below. Any expert advice on the below approach?
public class TableBuilder
{
private readonly Table _table = new();
public Table Build() => _table;
public TableBuilder WithWidth(int width)
{
_table.Width = width;
return this;
}
public TableBuilder WithLength(int length)
{
_table.Length = length;
return this;
}
}
public class RobotBuilder
{
private readonly Robot _robot = new();
public Robot Build() => _robot;
public RobotBuilder WithLocation(Point point)
{
_robot.CurrentLocation = point;
return this;
}
}
public class ControllerBuilder
{
private readonly Controller _controller = new();
private readonly TableBuilder _tableBuilder = new();
private readonly RobotBuilder _robotBuilder = new();
public Controller Build() => _controller;
public ControllerBuilder WithTable(int width, int length)
{
_controller.Table = _tableBuilder.WithWidth(width)
.WithLength(length)
.Build();
return this;
}
public ControllerBuilder WithRobot(Point point)
{
_controller.Robot = _robotBuilder.WithLocation(point)
.Build();
return this;
}
}
Finally I used below code to declare the Controller
var _controller = new ControllerBuilder()
.WithRobot(new Point(x, y))
.WithTable(5, 5)
.Build();
What I usually do in this cases is to use nested builders with lambdas, which are useful when the nested classes have many parameters needed at construction time:
public class Controller
{
private readonly Robot _robot;
private readonly Table _table;
public Controller(Robot robot, Table table)
{
_robot = robot;
_table = table;
}
public void Place()
{
}
public void Action()
{
}
}
public class Robot
{
private Point _currentLocation;
public Robot(Point point)
{
}
public void Move()
{
}
}
public class Table
{
private readonly int _width;
private readonly int _length;
public Table(int width, int length)
{
_width = width;
_length = length;
}
public bool IsValidLocation(Point point)
{
return false;
}
}
public class TableBuilder
{
private int _width;
private int _length;
public TableBuilder WithWidth(int width)
{
_width = width;
return this;
}
public TableBuilder WithLength(int length)
{
_length = length;
return this;
}
public Table Build() => new Table(_width, _length);
}
public class RobotBuilder
{
private Point _location;
public Robot Build() => new Robot(_location);
public RobotBuilder WithLocation(Point location)
{
_location = location;
return this;
}
}
public class ControllerBuilder
{
private Robot _robot;
private Table _table;
public Controller Build() => new Controller(_robot, _table);
public ControllerBuilder WithRobot(Func<RobotBuilder, RobotBuilder> builderDirector)
{
_robot = builderDirector.Invoke(new RobotBuilder()).Build();
return this;
}
public ControllerBuilder WithTable(Func<TableBuilder, TableBuilder> builderDirector)
{
_table = builderDirector(new TableBuilder()).Build();
return this;
}
}
public class Program
{
public static void Main()
{
var controller = new ControllerBuilder()
.WithTable(builder => builder.WithLength(1).WithWidth(2))
.WithRobot(builder => builder.WithLocation(new Point(1,1)))
.Build();
}
}