I'm trying to understand fluent builder pattern by creating the person builder object below. I've written the code as I would like to use it but am having issues with implementing it. My issues are as follows:
- When calling
HavingJob()
, this should create a new job that can then be configured using only applicable methods for a job and ultimately added to theJobs
collection of the person. It feels like should return it so that other fluent job methods can be called on it. Not sure how to implement that awhile allowing chaining at that level and above. - When implementing the
IJobBuilder
methods, I don't have access to the specific job they created in theHavingJob()
method because I need to return theIJobBuilder
to restrict the fluent methods to only be the ones related to the job. What is the trick toHavingJob()
so that those specific job methods can operate on a specific job while still allowing for chaining? - Once I go down a fluent path that ends with
IJobBuilder
, I can no longer callBuild()
orHavingJob()
to add additional jobs. Would the answer to that one be to have a separate implementation ofIJobBuilder
that inherits fromPersonBuilder
?
public class Person
{
public string Name { get; set; }
public List<Job> Jobs { get; set; }
public List<Phone> Phones { get; set; }
}
public class Phone
{
public string Number { get; set; }
public string Usage { get; set; }
}
public class Job
{
public string CompanyName { get; set; }
public int Salary { get; set; }
}
class Program
{
static void Main(string[] args)
{
var p = PersonBuilder
.Create()
.WithName("My Name")
.HavingPhone("222-222-2222")
.WithUsage("CELL")
.HavingJob()
.WithCompanyName("First Company")
.WithSalary(100)
.HavingJob()
.WithCompanyName("Second Company")
.WithSalary(200)
.Build();
Console.WriteLine(JsonConvert.SerializeObject(p));
}
}
public class PersonBuilder : IJobBuilder
{
protected Person Person;
public PersonBuilder() { Person = new Person(); }
public static PersonBuilder Create() => new PersonBuilder();
public PersonBuilder WithName(string name)
{
Person.Name = name;
return this;
}
public PersonBuilder HavingPhone(string phoneNumber)
{
// Need instance of phone
return this;
}
public PersonBuilder WithUsage(string phoneUsage)
{
// Need instance of phone
return this;
}
public IJobBuilder HavingJob()
{
// Need to create a job here and return it so that IJobBuilder methods work on specific instance right?
return this;
}
public Person Build() => Person;
public IJobBuilder WithCompanyName(string companyName)
{
// How do I set the company name if I don't have the job instance here
job.CompanyName = companyName;
return this;
}
public IJobBuilder WithSalary(int amount)
{
// How do I set the salary if I don't have a specific job instance here
job.Salary = amount;
return this;
}
}
public interface IJobBuilder
{
IJobBuilder WithCompanyName(string companyName);
IJobBuilder WithSalary(int salary);
}