Skip to content

Commit 0ee8cb0

Browse files
committed
Add abstract renderer example
1 parent 5e4506c commit 0ee8cb0

1 file changed

Lines changed: 137 additions & 0 deletions

File tree

‎JavaScript/1-renderer.js‎

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
'use strict';
2+
3+
// Abstract class or Interface
4+
5+
class Renderer {
6+
constructor() {
7+
this.output = [];
8+
}
9+
10+
header(s) {
11+
console.dir({ header: [s] });
12+
throw new Error('Renderer.header is not implemented');
13+
}
14+
15+
paragraph(s) {
16+
console.dir({ paragraph: [s] });
17+
throw new Error('Renderer.paragraph is not implemented');
18+
}
19+
20+
table(array) {
21+
console.dir({ table: [array] });
22+
throw new Error('Renderer.table is not implemented');
23+
}
24+
25+
toString() {
26+
return this.output.join('\n');
27+
}
28+
}
29+
30+
// Multiple implementations
31+
32+
class HtmlRenderer extends Renderer {
33+
header(s) {
34+
this.output.push(`<h1>${s}</h1>`);
35+
}
36+
37+
paragraph(s) {
38+
this.output.push(`<p>${s}</p>`);
39+
}
40+
41+
table(array) {
42+
const columns = Object.keys(array[0]);
43+
const header = columns.map(s => `<th>${s}</th>`);
44+
const rows = array.map(obj => columns.map(col => `<td>${obj[col]}</td>`));
45+
const tr = cells => `<tr>${cells.join('')}</tr>`;
46+
const result = [header].concat(rows).map(tr).join('\n');
47+
this.output.push(`<table>\n${result}\n</table>`);
48+
}
49+
}
50+
51+
class MarkdownRenderer extends Renderer {
52+
header(s) {
53+
this.output.push(`# ${s}\n`);
54+
}
55+
56+
paragraph(s) {
57+
this.output.push(s + '\n');
58+
}
59+
60+
table(array) {
61+
const columns = Object.keys(array[0]);
62+
const header = columns.map(s => `${s}`);
63+
const separator = columns.map(() => '---');
64+
const rows = array.map(obj => columns.map(col => `${obj[col]}`));
65+
const tr = cells => `${cells.join(' | ')}`;
66+
const result = [header, separator].concat(rows).map(tr).join(' |\n| ');
67+
this.output.push('| ' + result + ' |\n');
68+
}
69+
}
70+
71+
// Abstract Usage
72+
73+
class Document {
74+
constructor(Renderer) {
75+
this.renderer = new Renderer();
76+
}
77+
78+
generate() {
79+
throw new Error('Document.generate is not implemented');
80+
}
81+
82+
print() {
83+
const result = this.renderer.toString();
84+
console.log(result);
85+
}
86+
}
87+
88+
// Implementations
89+
90+
class Persons extends Document {
91+
generate({ title, description, list }) {
92+
this.renderer.header(title);
93+
this.renderer.paragraph(description);
94+
this.renderer.table(list);
95+
}
96+
}
97+
98+
class Letter extends Document {
99+
generate({ from, to, subject, content }) {
100+
this.renderer.header(`Subject: ${subject}`);
101+
this.renderer.paragraph(`From: ${from}`);
102+
this.renderer.paragraph(`To: ${to}`);
103+
this.renderer.paragraph('Hello');
104+
this.renderer.paragraph(content);
105+
this.renderer.paragraph('Best regards');
106+
}
107+
}
108+
109+
// Usage example 1
110+
111+
const persons = new Persons(MarkdownRenderer);
112+
persons.generate({
113+
title: 'Great Thinkers',
114+
description: 'Here is a list of the greatest thinkers of mankind',
115+
list: [
116+
{ name: 'Marcus Aurelius', city: 'Rome', born: 121 },
117+
{ name: 'Victor Glushkov', city: 'Rostov on Don', born: 1923 },
118+
{ name: 'Ibn Arabi', city: 'Murcia', born: 1165 },
119+
{ name: 'Mao Zedong', city: 'Shaoshan', born: 1893 },
120+
{ name: 'Rene Descartes', city: 'La Haye en Touraine', born: 1596 },
121+
]
122+
});
123+
persons.print();
124+
125+
// Usage example 2
126+
127+
const letter = new Letter(HtmlRenderer);
128+
letter.generate({
129+
from: 'Marcus Aurelius',
130+
to: 'Rene Descartes',
131+
subject: 'Meditations: Book 2',
132+
content: `When you wake up in the morning, tell yourself:
133+
The people I deal with today will be meddling, ungrateful,
134+
arrogant, dishonest, jealous, and surly. They are like this
135+
because they can’t tell good from evil.`
136+
});
137+
letter.print();

0 commit comments

Comments
 (0)