-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path1-basic.js
More file actions
129 lines (105 loc) · 3.65 KB
/
1-basic.js
File metadata and controls
129 lines (105 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
'use strict';
// Composite is a design pattern to create part-whole hierarchies of entities
// so that the parts and composites can be treated uniformly and transparently
// by the client.
// Main components of the Composite pattern are a 'component' interface which
// declares common operations, 'composite' which represents a container and
// typically delegates all operations to its children and a 'leaf' that
// represents the end of the hierarchy, implements operations and usually
// contains no children.
// The example here represents View hierarchy using the Composite pattern to
// uniformly treat all components.
class ViewComponent {
draw() {
throw new Error('Not implemented');
}
// Another option would be to have the add/remove/iterate methods be in the
// component itself (here) this allows for more transparency (no difference
// between 'leaf' and 'composite' for the client but may lead to errors, like
// adding a child to a leaf node that doesn't support it).
//
// One more option would be to declare an `getComposite()` method here with
// default implementation to allow checks for whether object is a composite
// or a leaf. However this would break the transparency/uniformity of the
// hierarchy.
}
class ViewComposite extends ViewComponent {
// This composite represents children as an Array which is not a requirement.
// They may be contained in an arbitrary stucture with or without the defined
// order depending on the application and requirements.
#children = [];
add(child) {
// May be checked if the `child` is already present in this composite.
// May be checked if the `child` is already present in the other composite
// to disallow sharing of children. This may require children to also
// contain 'parent' references or at least isChild status.
this.#children.push(child);
}
remove(child) {
this.#children.remove(child);
}
draw() {
// Simply delegate the operation to the children.
this.#children.forEach(child => child.draw());
}
// Can also be present if it is possible and needed to get a specific child.
// This way every child should have a unique Id and Map can be used to store
// the children.
// get(id) {}
[Symbol.iterator]() {
return this.#children[Symbol.iterator]();
}
}
class DecoratorComposite extends ViewComposite {
draw() {
// Not only delegate the operation but also augment the behavior.
console.log('NestedStart');
super.draw();
console.log('NestedEnd');
}
}
class PrintLeaf extends ViewComponent {
constructor(text) {
super();
this.text = text;
}
draw() {
console.log(this.text);
}
}
// Usage. As we can see all relevant methods are called transparently on
// Composites or Leaves
const hello = new PrintLeaf('hello');
const world = new PrintLeaf('world');
const js = new PrintLeaf('js');
const helloView = new ViewComposite();
helloView.add(hello);
helloView.add(world);
const jsView = new ViewComposite();
jsView.add(world);
jsView.add(js);
const nestedView = new DecoratorComposite();
nestedView.add(helloView);
nestedView.add(jsView);
console.group('Leaf component .draw()');
hello.draw();
console.groupEnd();
console.log();
console.group('Composite component .draw()');
helloView.draw();
console.groupEnd();
console.log();
console.group('Another Composite component .draw()');
jsView.draw();
console.groupEnd();
console.log();
console.group('Composite of composites component .draw()');
nestedView.draw();
console.groupEnd();
console.log();
console.group('Composite of composites component iterate children');
for (const child of nestedView) {
child.draw();
}
console.groupEnd();
console.log();