Implementation of the Builder pattern
In this article, we will look at the implementation of Builder pattern with Typescript. The problem we will solve is about creating a football team step-by-step.
As written in “Design Patterns: Elements of Reusable Object-Oriented Software”, the intent of the Builder pattern is to separate the construction of a complex object from its representation, so that the same construction process can create different representations.
We know that a football team consists of goalkeepers, defenders, midfielders, and attackers. During transfer windows, teams are allowed to transfer new players and enforce the team. In order to represent a player, we will create an interface TeamMember. It includes a name of type string and a role of type TeamRole, which is an enum.
export interface TeamMember {
name: string,
role: TeamRole
}
export enum TeamRole {
Goalkeeper = 'goalkeeper', Defender = 'defender',
Midfielder = 'midfielder', Attacker = 'attacker'
}
Next, we will set up our TeamCreator that is the builder of this simple application.
export class TeamCreator {
private goalkeepers: TeamMember[] = [];
private defenders: TeamMember[] = [];
private midfielders: TeamMember[] = [];
private attackers: TeamMember[] = [];
...
We will use arrays of type TeamMember to group our goalkeepers, defenders, midfielders and attackers. Now we need to create the operation for building our team.
...
public addMember(member: TeamMember): void {
console.log(`adding member named ${member.name}`);
switch (member.role) {
case TeamRole.Attacker:
this.attackers.push(member);
break;
case TeamRole.Defender:
this.defenders.push(member);
break;
case TeamRole.Midfielder:
this.midfielders.push(member);
break;
case TeamRole.Goalkeeper:
this.goalkeepers.push(member);
break;
default:
break;
}
}
...
Method addMember expects a parameter of type TeamMember and after it checks its role, adds it in the appropriate array. What is missing now, is the result operation. What differs the Builder pattern from the Abstract Factory pattern, is that the Builder pattern returns the product as a final step , while the Abstract Factory pattern returns it immediately.
...
public getResult(): string {
return `Team currently includes:
goalkeepers => ${this.goalkeepers.map(value => value.name)}
defenders => ${this.defenders.map(value => value.name)}
midfielders => ${this.midfielders.map(value => value.name)}
attackers => ${this.attackers.map(value => value.name)}`;
}
}
...
Now that we have our Builder, we can build our team step-by-step as in the following example. We are able to get our result after the first transfer window and look at the team and the players we currently have. After the January transfer window is opened, we add new players and we check the result at the end. Using the Builder pattern, the algorithm for creating our complex object is independent of the parts that make up the object and how they’re assembled. Another benefit of the Builder pattern is that the construction process allows different representations for the object that is constructed. As we can see, our two representations of the object are during the first and second transfer window.
...
const potentialTeamMembers: TeamMember[] = [
{
name: 'Gigi Buffon',
role: TeamRole.Goalkeeper
},
{
name: 'Sergio Aguero',
role: TeamRole.Attacker
},
{
name: 'Zlatan Ibrahimovic',
role: TeamRole.Attacker
},
{
name: 'Romelo Lukaku',
role: TeamRole.Attacker
},
{
name: 'Bruno Fernandes',
role: TeamRole.Midfielder
},
{
name: 'Leonardo Bonucci',
role: TeamRole.Defender
},
{
name: 'Ruben Dias',
role: TeamRole.Defender
},
... many other players available for transfer
]
const teamCreator: TeamCreator = new TeamCreator();
console.log('July transfer window is opened.')
potentialTeamMembers.slice(0, 5).forEach(member => {
teamCreator.addMember(member);
})
console.log('Transfer window closed!');
console.log(teamCreator.getResult());
console.log('January transfer window is opened.');
potentialTeamMembers.slice(5).forEach(member => {
teamCreator.addMember(member);
})
console.log('Transfer window closed!');
console.log(teamCreator.getResult());
...
For more similar content, check out https://lejdiprifti.web.app