Composite Design Pattern
Structural: Composite Pattern
What is the composite design pattern in Modern JavaScript?
View Answer:
class Component {
constructor(name) {
this._name = name;
}
getNodeName() {
return this._name;
}
// This method should be overridden by the Composite class
add() {}
// This method should be overridden by the Composite class
remove() {}
// This method should be overridden by the Leaf class
display() {}
}
class Leaf extends Component {
constructor(name) {
super(name);
}
// Override the display method of the Component class
display(depth = 0) {
console.log(`${"-".repeat(depth)}${this._name}`);
}
}
class Composite extends Component {
constructor(name) {
super(name);
this._children = [];
}
// Override the add method of the Component class
add(component) {
this._children.push(component);
}
// Override the remove method of the Component class
remove(component) {
const componentIndex = this._children.indexOf(component);
if (componentIndex !== -1) {
this._children.splice(componentIndex, 1);
}
}
// Override the display method of the Component class
display(depth = 0) {
console.log(`${"-".repeat(depth)}${this._name}`);
for (let i = 0; i < this._children.length; i++) {
this._children[i].display(depth + 2);
}
}
}
// Example usage
const tree = new Composite("root");
const branch1 = new Composite("branch1");
const branch2 = new Composite("branch2");
const leaf1 = new Leaf("leaf1");
const leaf2 = new Leaf("leaf2");
const leaf3 = new Leaf("leaf3");
branch1.add(leaf1);
branch1.add(leaf2);
branch2.add(leaf3);
tree.add(branch1);
tree.add(branch2);
tree.display();
In this example, we're creating a tree-like structure. Each 'branch' can contain other branches or leaves, but leaves can't contain other components. When the display method is called on the root node, it recursively displays all of its children.
Where is the Composite Design Pattern commonly used?
View Answer:
The Composite pattern belongs to which design pattern family?
View Answer:
Can you specify a use case for the Composite Pattern?
View Answer:
Let's consider a scenario where we want to represent a nested menu structure using composite pattern. Each menu could contain other submenus or menu items (which cannot contain anything).
Here is an example in modern JavaScript:
class MenuComponent {
constructor(name) {
this._name = name;
}
getName() {
return this._name;
}
add() {}
remove() {}
display() {}
}
class MenuItem extends MenuComponent {
constructor(name, url) {
super(name);
this._url = url;
}
display() {
console.log(`${this._name}: ${this._url}`);
}
}
class SubMenu extends MenuComponent {
constructor(name) {
super(name);
this._menuComponents = [];
}
add(menuComponent) {
this._menuComponents.push(menuComponent);
}
remove(menuComponent) {
const menuComponentIndex = this._menuComponents.indexOf(menuComponent);
if (menuComponentIndex !== -1) {
this._menuComponents.splice(menuComponentIndex, 1);
}
}
display() {
console.log(`${this._name}`);
for (let i = 0; i < this._menuComponents.length; i++) {
this._menuComponents[i].display();
}
}
}
// Example usage
const mainMenu = new SubMenu("Main Menu");
const fileMenu = new SubMenu("File");
const newFile = new MenuItem("New", "/file/new");
const openFile = new MenuItem("Open", "/file/open");
fileMenu.add(newFile);
fileMenu.add(openFile);
const editMenu = new SubMenu("Edit");
const cut = new MenuItem("Cut", "/edit/cut");
const copy = new MenuItem("Copy", "/edit/copy");
editMenu.add(cut);
editMenu.add(copy);
mainMenu.add(fileMenu);
mainMenu.add(editMenu);
mainMenu.display();
In this example, we're creating a menu-like structure. Each 'SubMenu' can contain other 'SubMenu' objects or 'MenuItem' objects, but 'MenuItem' objects can't contain other components. When the display method is called on the main menu, it recursively displays all of its children.
What objects participate in the Composite Pattern?
View Answer:
In the Composite Pattern, there are typically three roles that objects can take on:
Component: This is a base class that defines the common interface for both simple (Leaf) and complex (Composite) objects in the composition.
Leaf: These are the basic elements of the composition and do not have their own sub-elements.
Composite: These are elements that can have sub-elements. Composites contain leaf elements and other composites.
Here's a code example in modern JavaScript demonstrating these roles:
// Component
class Graphic {
constructor(name) {
this._name = name;
}
getName() {
return this._name;
}
draw() {}
add() {}
remove() {}
}
// Leaf
class Circle extends Graphic {
constructor(name) {
super(name);
}
draw() {
console.log(`Draw ${this._name}`);
}
}
// Composite
class CompoundGraphic extends Graphic {
constructor(name) {
super(name);
this._children = [];
}
add(graphic) {
this._children.push(graphic);
}
remove(graphic) {
const graphicIndex = this._children.indexOf(graphic);
if (graphicIndex !== -1) {
this._children.splice(graphicIndex, 1);
}
}
draw() {
console.log(`Draw ${this._name}`);
for (let i = 0; i < this._children.length; i++) {
this._children[i].draw();
}
}
}
// Example usage
const circle1 = new Circle("circle1");
const circle2 = new Circle("circle2");
const graphic = new CompoundGraphic("graphic");
graphic.add(circle1);
graphic.add(circle2);
graphic.draw();
In this example, Graphic
is the Component, Circle
is the Leaf, and CompoundGraphic
is the Composite. You can see how CompoundGraphic
can contain both Leaf (i.e., Circle
) and Composite (i.e., other CompoundGraphic
) objects, and work with them uniformly via the draw
method.
What is the purpose of the 'Component' in the Composite Design Pattern?
View Answer:
How does the 'Leaf' in Composite Design Pattern function?
View Answer:
What is the role of 'Composite' in the Composite Design Pattern?
View Answer:
How does Composite Design Pattern handle adding or removing components?
View Answer:
What are some of the advantages of employing the composite pattern?
View Answer:
- Using polymorphism and recursion, you can more efficiently work with complex tree structures.
- The Open/Closed Principle You can add new element types to the app without breaking the existing code, which is now compatible with the object tree.
What are some of the disadvantages of employing the composite pattern?
View Answer:
- It might be challenging to provide a standard interface for classes whose functionality differs too much. You would need to overgeneralize the component interface in specific scenarios, making it harder to comprehend.