Typescript 組合模式(Composite)

標籤: 前端 設計模式 組合模式 typescript composite


請仔細閱讀下面代碼,理解其中的設計理念。

組合模式

組合模式: 將對象組合成樹形結構以表示“部分整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。

實際場景

爲了方便我們對多個文件的管理,我們引入了“文件夾-文件”的模式。將具有統一性質的文件放入一個文件夾中,將具有統一性質的文件夾再放入另一個文件夾中。可以對整個文件夾系統進行文件的搜索,也可以對某一個文件夾進行搜索。讓文件管理變得簡單。
而“文件夾-文件”這種結構就是典型 的組合模式。

組合模式的結構

  • Component 是組合中的對象聲明接口,在適當的情況下,實現所有類共有接口的默認行爲。聲明一個接口用於訪問和管理Component子部件。
  • Leaf 在組合中表示葉子結點對象,葉子結點沒有子結點。
  • Composite 定義有枝節點行爲,用來存儲子部件,在Component接口中實現與子部件有關操作,如增加(add)和刪除(remove)等。

組合模式的例子

現在要實現一個文件夾文件樹

Node枚舉

/* node-type-enum.ts */
enum NodeTypeEnum {
    ImageFile = 'image',
    TextFile = 'text',
    Folder = 'folder',
}

export {
    NodeTypeEnum
}

Node抽象類

/* abstract-node.ts */
import { NodeTypeEnum } from './node-type-enum';

export abstract class AbstractNode {
    protected name: string;
    protected type: NodeTypeEnum;
    protected children: AbstractNode[];

    public abstract add(node: AbstractNode): AbstractNode;
    public abstract getFileDeep(name: string): AbstractNode;
}

文件和文件夾基礎類

/* basic-file-folder.ts */
import { AbstractNode } from './abstract-node';
import { NodeTypeEnum } from './node-type-enum';

export abstract class BasicFile extends AbstractNode {
    public add (file: BasicFile): BasicFile {
        console.error('文件類型不支持添加');
        return this;
    }

    public getFileDeep (name: string): BasicFile {
        if (name === this.name) {
            return this;
        }
        return null;
    }
}

export abstract class BasicFolder extends AbstractNode {
    protected constructor () {
        super();
        this.type = NodeTypeEnum.Folder;
        this.children = [];
    }

    public add (file: AbstractNode): BasicFolder {
        this.children.push(file);
        return this;
    }

    public getFileDeep (name: string): AbstractNode {
        if (this.name === name) {
            return this;
        }
        for (let index = 0; index < this.children.length; index++) {
            const node = this.children[index].getFileDeep(name);
            if (node) {
                return node;
            }
        }
        return null;
    }
}

文件類

/* files.ts */
import { BasicFile } from './basic-file-folder';
import { NodeTypeEnum } from './node-type-enum';

export class ImageFile extends BasicFile {
    constructor (name: string) {
        super();
        this.name = name;
        this.type = NodeTypeEnum.ImageFile;
    }
}

export class TextFile extends BasicFile {
    constructor (name: string) {
        super();
        this.name = name;
        this.type = NodeTypeEnum.TextFile;
    }
}

文件夾類

/* folder.ts */
import { BasicFolder } from './basic-file-folder';

export default class SystemFolder extends BasicFolder{
    constructor(name){
        super();
        this.name = name;
    }
}

客戶端

/* client.ts */
import { ImageFile, TextFile } from './files';
import SystemFolder from './folder';

export default class Client {
    public static initTree (): SystemFolder {
        const folder1: SystemFolder = new SystemFolder('根文件夾');
        const folder2: SystemFolder = new SystemFolder('圖像文件夾');
        const folder3: SystemFolder = new SystemFolder('文本文件夾');

        const image1: ImageFile = new ImageFile('a.jpg');
        const image2: ImageFile = new ImageFile('b.jpg');

        const text1: TextFile = new TextFile('a.txt');
        const text2: TextFile = new TextFile('b.txt');

        folder2.add(image1).add(image2);
        folder3.add(text1).add(text2);
        folder1.add(folder2).add(folder3);

        return folder1;
    }
}
const tree = Client.initTree();
const aJpg = tree.getFileDeep('a.jpg');
console.log(aJpg);

組合模式的利弊

利:

  • 減少大量手工遍歷數組或其他數據的粘合性代碼
  • 組合模式中各個對象耦合非常鬆散,更容易改變他們或互換位置,有利於代碼重構
  • 讓代碼有一個出色的層次體系,客戶端調用更方便

弊:
組合模式掩蓋了他所支持的每一種操作的代價。如果層次體系很大的話,系統的性能將會收到影響。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章