组合模式
约 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();