標籤: 前端 設計模式 組合模式 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);
組合模式的利弊
利:
- 減少大量手工遍歷數組或其他數據的粘合性代碼
- 組合模式中各個對象耦合非常鬆散,更容易改變他們或互換位置,有利於代碼重構
- 讓代碼有一個出色的層次體系,客戶端調用更方便
弊:
組合模式掩蓋了他所支持的每一種操作的代價。如果層次體系很大的話,系統的性能將會收到影響。