Composite pattern: Also known as the partial-whole pattern, objects are grouped into a tree structure to represent a partial-whole hierarchy. Through the polymorphism of objects, users can use single objects and combined objects consistently.

Life: file directory, DOM document tree

Model features

  1. Represents the hierarchical structure of “parts-whole”, generating a “leaf” structure;
  2. Consistent operation, the leaf object external interface is consistent (consistent operation and data structure);
  3. The top-down flow of requests from tree objects to leaf objects;
  4. The invocation of the top-level object traverses the execution of the leaf object below it.

Code implementation

Tree object and leaf object interface unified, tree object added a cache array, store the leaf object. When a tree object method is executed, the request is passed to its underlying object for execution.

// Tree object - file directory
class CFolder {
    constructor(name) {
        this.name = name;
        this.files = [];
    }

    add(file) {
        this.files.push(file);
    }

    scan() {
        for (let file of this.files) { file.scan(); }}}// Leaf object - file
class CFile {
    constructor(name) {
        this.name = name;
    }

    add(file) {
        throw new Error('File cannot be added under file');
    }

    scan() {
        console.log('Start scanning files:The ${this.name}`); }}let mediaFolder = new CFolder('entertainment');
let movieFolder = new CFolder('movie');
let musicFolder = new CFolder('music');

let file1 = new CFile('Iron Man. Mp4');
let file2 = new CFile('More on memory.mp3');
movieFolder.add(file1);
musicFolder.add(file2);
mediaFolder.add(movieFolder);
mediaFolder.add(musicFolder);
mediaFolder.scan();

/* Output: Start scanning files: Iron Man.mp4 Start scanning files: Talk about Memory.mp3 */
Copy the code

The CFolder interface must be consistent with the CFile interface. If a tree object is found during scan(), scan() continues to traverse the leaf object beneath it.

JavaScript is different from other static programming languages. The difficulty of implementing composite pattern is to keep the interface between tree object and leaf object unified. TypeScript interface specification can be customized to achieve type constraints.

// Define the interface specification
interface Compose {
    name: string,
    add(file: CFile): void,
    scan(): void
}

// Tree object - file directory
class CFolder implements Compose {
    fileList = [];
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    add(file: CFile) {
        this.fileList.push(file);
    }

    scan() {
        for (let file of this.fileList) { file.scan(); }}}// Leaf object - file
class CFile implements Compose {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    add(file: CFile) {
        throw new Error('File cannot be added under file');
    }

    scan() {
        console.log('Start scanning:${this.name}`)}}let mediaFolder = new CFolder('entertainment');
let movieFolder = new CFolder('movie');
let musicFolder = new CFolder('music');

let file1 = new CFile('Iron Man. Mp4');
let file2 = new CFile('More on memory.mp3');
movieFolder.add(file1);
musicFolder.add(file2);
mediaFolder.add(movieFolder);
mediaFolder.add(musicFolder);
mediaFolder.scan();

/* Output: Start scanning files: Iron Man.mp4 Start scanning files: Talk about Memory.mp3 */
Copy the code

Transparency security issues

The transparency of the composite pattern means that the leaf object interface remains uniform and does not need to be distinguished by external calls. However, this can cause some problems, as in the file directory example above, no more files can be added to the file (leaf object), so you need to throw an exception in the add() method of the file class as a reminder.

Pitfalls to avoid

1. Composition is not inheritance, and leaf objects are not parent-child objects

The tree structure of the composite pattern IS A has-A (aggregation) relationship, not IS-A. The key for leaf objects to cooperate is that they maintain a unified external interface, rather than the leaf object inheriting the property method of the tree object. The relationship between the two is not parent-child.

2. Maintain consistency in leaf object operations

In addition to interface consistency with tree objects, the operations of leaf objects must also be consistent. A leaf can grow only on one tree. When a top-level object is called, each leaf object can receive only one request, and a leaf object cannot be dependent on multiple tree objects.

3. The leaf object achieves bubbling transfer

Request passing is passed from tree to leaf. If you want to reverse the passing process, you need to keep a reference to the tree object in the leaf and bubble it to the tree object for processing.

4. Not just a simple subset traversal

When an object’s interface method is called, if it is a tree object, the request is passed to a leaf object, which executes the method, and so on. Unlike the iterator pattern, iterator pattern traversal does not conduct request conduction.

Application scenarios

  1. Optimize processing of recursive or hierarchical data structures (file system – directory file management);
  2. Use in conjunction with other design patterns, such as command patterns to implement “macro commands”.

The advantages and disadvantages

  • Advantages:
    • Ignoring the difference between a composite object and a single object, the external consistent interface is used.
    • Decouple the connections between the caller and the complex elements, and the processing becomes simple.
  • disadvantages
    • The leaf object interface is consistent and cannot be distinguished except at runtime.
    • Creating too many wrap objects adds an additional memory burden.

Refer to the article

  • JavaScript Design Patterns and Development Practices

Github is looking forward to Star! Github.com/ZengLingYon…

Author: in the name of music this article is original, there are inappropriate places welcome to point out. Reprint please indicate the source.