跳至主要內容

组合模式

约 568 字

组合模式

核心思想

组合模式允许将对象组合成树状结构,并能像使用独立对象一样使用它们。

典型用例

文件和目录结构

在文件系统中,可以用相同的方式来处理文件和目录。目录可以包含文件和其他目录,而文件是目录的一部分。这种模式允许客户端代码以统一的方式来处理复杂的树状结构。

在这个例子中,目录和文件都继承自共同的抽象组件类,目录可以包含其他目录或文件对象,print方法可以递归的输出整个文件和目录结构,getSize方法可以计算整个目录的总大小。这样的设计使得对文件和目录的操作变得简单和统一。

// npm run code src/code/design-pattern/composite/directory-structure.ts

export {};

// 定义文件和目录共同的抽象组件类
abstract class FileSystemComponent {
    protected name: string;

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

    abstract getSize(): number;
    abstract print(indentation: string): void;
}

// 创建具体的组件类:文件类(叶子节点)
class MyFile extends FileSystemComponent {
    private size: number;

    constructor(name: string, size: number) {
        super(name);
        this.size = size;
    }

    getSize(): number {
        return this.size;
    }

    print(indentation: string): void {
        console.log(`${indentation}File: ${this.name}, Size: ${this.size}`);
    }
}

// 创建具体的组件类:目录类(复合节点)
class Directory extends FileSystemComponent {
    private components: FileSystemComponent[] = [];

    constructor(name: string) {
        super(name);
    }

    add(component: FileSystemComponent): void {
        this.components.push(component);
    }

    getSize(): number {
        return this.components.reduce((total, component) => total + component.getSize(), 0);
    }

    print(indentation: string): void {
        console.log(`${indentation}Directory: ${this.name}`);
        this.components.forEach(component => component.print(indentation + '  '));
    }
}

const rootDirectory = new Directory('root');
const file1 = new MyFile('file1.txt', 100);
const file2 = new MyFile('file2.txt', 200);
const subDirectory = new Directory('subdir');
const file3 = new MyFile('file3.txt', 300);

rootDirectory.add(file1);
rootDirectory.add(file2);
rootDirectory.add(subDirectory);
subDirectory.add(file3);

// 打印整个文件和目录结构
rootDirectory.print(''); 

// 获取并打印根目录的总大小
console.log(`Total size of root directory: ${rootDirectory.getSize()}`); 

图形绘制

组合模式允许将对象组合成树形结构以表示部分-整体的层次结构,因为它可以将简单的图形(如线条、矩形、圆形)组合成复杂的图形,所以非常适用于图形编辑器的场景。

// npm run code src/code/design-pattern/composite/graphic-rendering.ts

export {};

// Graphic 接口
interface Graphic {
    draw(): void;
}

// 线条类
class Line implements Graphic {
    draw(): void {
        console.log("Draw a line");
    }
}

// 矩形类
class Rectangle implements Graphic {
    draw(): void {
        console.log("Draw a rectangle");
    }
}

// 圆形类
class Circle implements Graphic {
    draw(): void {
        console.log("Draw a circle");
    }
}

// 组合图形类
class CompositeGraphic implements Graphic {
    private graphics: Graphic[] = [];

    add(graphic: Graphic) {
        this.graphics.push(graphic);
    }

    draw(): void {
        console.log("Composite Graphic:");
        for (let graphic of this.graphics) {
            graphic.draw();
        }
    }
}

// 使用示例
const line = new Line();
const rectangle = new Rectangle();
const circle = new Circle();

const composite = new CompositeGraphic();
composite.add(line);
composite.add(rectangle);
composite.add(circle);

composite.draw();

用户界面组件

在用户界面设计中,组合模式用于构建和管理复杂的 UI 组件树。例如,一个窗口(容器)可以包含面板、按钮和文本框,面板又可以包含其他组件。

// npm run code src/code/design-pattern/composite/user-interface-component.ts

export {};

// UIComponent 接口
interface UIComponent {
    render(): void;
    add?(component: UIComponent): void;
}

// 按钮类
class Button implements UIComponent {
    render(): void {
        console.log("Render a button");
    }
}

// 文本框类
class TextBox implements UIComponent {
    render(): void {
        console.log("Render a text box");
    }
}

// 面板类,可以包含其他组件
class Panel implements UIComponent {
    private components: UIComponent[] = [];

    add(component: UIComponent): void {
        this.components.push(component);
    }

    render(): void {
        console.log("Render a panel with its components:");
        for (const component of this.components) {
            component.render();
        }
    }
}

// 窗口类,作为顶层容器
class MyWindow implements UIComponent {
    private components: UIComponent[] = [];

    add(component: UIComponent): void {
        this.components.push(component);
    }

    render(): void {
        console.log("Render a window with its components:");
        for (const component of this.components) {
            component.render();
        }
    }
}

// 使用示例
const myWindow = new MyWindow();
const panel = new Panel();
const button = new Button();
const textBox = new TextBox();

panel.add(button);
panel.add(textBox);
myWindow.add(panel);

myWindow.render();

组织架构

在表示和管理组织架构时,如公司的部门和员工,一个部门可以包含子部门和员工,组合模式允许以统一的方式来处理部门和员工。

// npm run code src/code/design-pattern/composite/organizational-structure.ts

export {};

// OrganizationComponent 接口
interface OrganizationComponent {
    print(): void;
    add?(component: OrganizationComponent): void;
}

// Employee 类
class Employee implements OrganizationComponent {
    constructor(private name: string, private position: string) {}

    print(): void {
        console.log(`${this.name} works as ${this.position}`);
    }
}

// Department 类
class Department implements OrganizationComponent {
    private name: string;
    private components: OrganizationComponent[] = [];

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

    add(component: OrganizationComponent): void {
        this.components.push(component);
    }

    print(): void {
        console.log(`Department: ${this.name}`);
        for (const component of this.components) {
            component.print();
        }
    }
}

// 使用示例
const headOffice = new Department("Head Office");
const salesDepartment = new Department("Sales Department");
const itDepartment = new Department("IT Department");

const employee1 = new Employee("John Doe", "Manager");
const employee2 = new Employee("Jane Smith", "Sales Representative");
const employee3 = new Employee("Mike Johnson", "Developer");

salesDepartment.add(employee2);
itDepartment.add(employee3);
headOffice.add(employee1);
headOffice.add(salesDepartment);
headOffice.add(itDepartment);

headOffice.print();

语法树

在编译器设计中,组合模式可以用于构建和操作抽象语法树。在这个例子中,创建了一个简化的模型来表示不同类型的语法结构,如表达式、循环或判断语句。每个节点都可以是一个简单的表达式,也可以是一个更复杂的结构。

// npm run code src/code/design-pattern/composite/syntax-tree.ts

export {};

// SyntaxNode 接口
interface SyntaxNode {
    print(): void;
    add?(node: SyntaxNode): void;
}

// Expression 类
class Expression implements SyntaxNode {
    constructor(private expression: string) {}

    print(): void {
        console.log(`Expression: ${this.expression}`);
    }
}

// Loop 类
class Loop implements SyntaxNode {
    private nodes: SyntaxNode[] = [];

    add(node: SyntaxNode): void {
        this.nodes.push(node);
    }

    print(): void {
        console.log("Loop:");
        for (const node of this.nodes) {
            node.print();
        }
    }
}

// Conditional 类
class Conditional implements SyntaxNode {
    private nodes: SyntaxNode[] = [];

    add(node: SyntaxNode): void {
        this.nodes.push(node);
    }

    print(): void {
        console.log("Conditional:");
        for (const node of this.nodes) {
            node.print();
        }
    }
}

// 使用示例
const rootNode = new Loop();
const expr1 = new Expression("x > 0");
const conditional = new Conditional();
const expr2 = new Expression("x = x - 1");

conditional.add(expr2);
rootNode.add(expr1);
rootNode.add(conditional);

rootNode.print();

上次编辑于: