-
Notifications
You must be signed in to change notification settings - Fork 467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jalinson: Drop Everything & Learn Jul 31 - Aug 13 #29197
Comments
I continued with the same Udemy Course of the last time. Time Spent: 1h 10min Today I reinforced the concept of the Builder pattern. Which is a pattern that allows to build objects or structures in a step by step process. This useful for objects that needs to be built in a procedural way or should have different states along a process or has way too many properties to be initialized in a single call. I reinforced the 2 ways of using the builder pattern, Simple (Fluent and Not Fluent) and Complex (More builders inside) Also, had an exercise at the end of the lecture. Simple: const TAG_INDENT = 2;
class Tag {
constructor(name = '', text = '') {
this.name = name;
this.text = text;
this.children = [];
}
toStringImpl(indent) {
let html = [];
const INDENTATION = ' '.repeat(indent * TAG_INDENT);
html.push(`${INDENTATION}<${this.name}>\n`);
if (this.text.length > 0) {
html.push(' '.repeat(TAG_INDENT * (indent + 1)));
html.push(this.text);
html.push('\n');
}
for (let child of this.children) html.push(child.toStringImpl(indent + 1));
html.push(`${INDENTATION}</${this.name}>\n`);
return html.join('');
}
toString() {
return this.toStringImpl(0);
}
static create(name) {
return new HtmlBuilder(name);
}
}
class HtmlBuilder {
constructor(rootName) {
this.root = new Tag(rootName);
this.rootName = rootName;
}
// Non-fluent interface
addChild(childName, childText) {
const child = new Tag(childName, childText);
this.root.children.push(child);
}
addChildFluent(childName, childText) {
const child = new Tag(childName, childText);
this.root.children.push(child);
return this;
}
toString() {
return this.root.toString();
}
build() {
return this.root;
}
clear() {
this.root = new Tag(this.rootName);
}
}
// We can rewrite the code below using the builder pattern
const hello = 'hello';
let html = [];
// This is construction logic
html.push('<p>');
html.push('hello');
html.push('</p>');
console.log(html.join(''));
const words = ['hello', 'world']; // See how is getting complicated
html = [];
html.push('<ul>\n');
for (let word of words) html.push(` <li>${word}</li>\n`); // Same construction logic
html.push('</ul>');
console.log(html.join(''));
// New Approach using the builder pattern
let builder = new HtmlBuilder('ul');
for (let word of words) builder.addChild('li', word);
console.log(builder.toString());
// We can initialize from Tag
builder = Tag.create('ul');
for (let word of words) builder.addChild('li', word);
console.log(builder.toString());
builder.clear();
// Fluent interface
builder.addChildFluent('li', 'foo').addChildFluent('li', 'bar').addChildFluent('li', 'baz');
console.log(builder.toString()); Complex: class Person {
constructor() {
this.streetAddress = this.postcode = this.city = '';
this.companyName = this.position = '';
this.annualIncome = 0;
}
toString() {
return `Person lives at ${this.streetAddress}, ${this.city}, ${this.postcode}\nand works at ${this.companyName} as ${this.position} earning ${this.annualIncome}`;
}
}
class PersonBuilder {
constructor(person = new Person()) {
this.person = person;
}
get lives() {
return new PersonAddressBuilder(this.person);
}
get works() {
return new PersonJobBuilder(this.person);
}
build() {
return this.person;
}
}
class PersonJobBuilder extends PersonBuilder {
constructor(person) {
super(person);
}
at(companyName) {
this.person.companyName = companyName;
return this;
}
asA(position) {
this.person.position = position;
return this;
}
earning(annualIncome) {
this.person.annualIncome = annualIncome;
return this;
}
}
class PersonAddressBuilder extends PersonBuilder {
constructor(person) {
super(person);
}
at(streetAddress) {
this.person.streetAddress = streetAddress;
return this;
}
withPostcode(postcode) {
this.person.postcode = postcode;
return this;
}
in(city) {
this.person.city = city;
return this;
}
}
// Usage
const pb = new PersonBuilder();
const person = pb.lives
.at('123 London Road')
.in('London')
.withPostcode('SW12BC')
.works.at('Fabrikam')
.asA('Engineer')
.earning(123000)
.build();
console.log(person.toString()); Exercise: // Exercise
class CodeBuilder {
constructor(className) {
this.className = className;
this.fields = [];
}
addField(name) {
this.fields.push(name);
return this;
}
toString() {
const mappedFields =
this.fields.map((field) => ` this.${field} = ${field};`).join('\n') + '\n }\n';
const constructor = this.fields.length
? ` constructor(${this.fields.join(', ')}) {\n${mappedFields}`
: '';
const classString = `class ${this.className} {\n${constructor}}`;
return classString;
}
}
let cb = new CodeBuilder('Person');
cb.addField('name').addField('age');
console.log(cb.toString());
// Output:
// class Person {
// constructor(name, age) {
// this.name = name;
// this.age = age;
// }
// }
// Empty class
cb = new CodeBuilder('Foo');
console.log(cb.toString());
// Output:
// class Foo {
// } |
No description provided.
The text was updated successfully, but these errors were encountered: