One of the most used patterns in the software development world is Builder pattern which is under the Creational category of design patterns.
The philosophy of this pattern is to separate between an object and its creating process especially for those objects which are complex and need more steps and complex validations to be created so we need to breakdown these steps and transfer them into another place. By doing so, we can have more control over the object's creation process and the validity of it, and more importantly, we will have a simple code to test and read and maintain.
Another benefit that we can get from this pattern is that by using it, as we decoupled the higher-level components from the object's direct constructor, in case of needing to add or remove steps to the process of building we can do it in just one single point, and we don't have to worry about the different ways of creating the object in different components.
Let's get started with a very simple code in javascript. Consider bellow code:
var PersonBuilder = (function () {
_person = {}; //Imagine this is a complex object and needs a variety of validations
function PersonBuilder() {}; //constrcutor
PersonBuilder.prototype.setName = function (name, family) {
if (!name)
throw new Error('Parameter "name" should not be null');
if (!family)
throw new Error('Parameter "family" should not be null');
_person.name = name;
_person.family = family;
return this;
};
PersonBuilder.prototype.setAge = function (age) {
if (age <= 0)
throw new Error('Age is not valid');
_person.age = age;
return this;
};
PersonBuilder.prototype.checkPersonValidation = function () {
if (_person.age == undefined)
throw new Error("the Age of the person has not been set. Please use 'setAge' before getting the person object");
if (!_person.name || !_person.family)
throw new Error("the name and family of the person have not been set. Please use 'setName' before getting the person object");
};
PersonBuilder.prototype.getPerson = function () {
this.checkPersonValidation();
return _person;
};
return PersonBuilder;
}());
Now we have:
let builder = new PersonBuilder();
builder.setAge(30);
builder.setName("foo", "fighters");
//Or we can use it as chaining way like this
builder.setAge(30).setName("foo", "fighters");
let person = builder.getPerson();
console.log(person)
/*
{
age: 30,
family: "fighters",
name: "foo"
}
*/
If you use invalid parameters or skip one of those steps you will get this result for example:
let builder = new PersonBuilder();
builder.setAge(30);
let person = builder.getPerson();
//Uncaught Error: the name and family of the person have not been set. Please use 'setName' before getting the person object"
Of course, the 'person' here is an elementary object because I kept this in this way for the sake of simplicity but when the destination object is complex, this pattern will become very handy.
I hope you now have a better understanding of this pattern and please leave a comment if you have any suggestion.
Top comments (0)