الـ Composite Pattern معناه ببساطة:
إنك تعامل مع objects أفراد و groups بنفس الطريقة.
زي file system:
- File (فرد)
- Folder (مجموعة من files و folders)
بتعاملهم بنفس الواجهة.
دون Composite:
if (isFile) {
file.delete();
} else if (isFolder) {
for (const item of folder.items) {
item.delete();
}
}مع Composite:
fileOrFolder.delete(); // نفس الكود للاثنينComponent interface:
interface FileSystemComponent {
getName(): string;
getSize(): number;
display(): void;
}Leaf (File):
class File implements FileSystemComponent {
constructor(private name: string, private size: number) {}
getName(): string { return this.name; }
getSize(): number { return this.size; }
display(): void { console.log(`File: ${this.name}`); }
}Composite (Folder):
class Folder implements FileSystemComponent {
private items: FileSystemComponent[] = [];
constructor(private name: string) {}
add(item: FileSystemComponent): void { this.items.push(item); }
getSize(): number {
return this.items.reduce((sum, item) => sum + item.getSize(), 0);
}
display(): void {
console.log(`Folder: ${this.name}`);
for (const item of this.items) {
item.display();
}
}
}الاستخدام:
const root = new Folder("root");
root.add(new File("file1.txt", 10));
root.add(new File("file2.txt", 20));
const subFolder = new Folder("subfolder");
subFolder.add(new File("file3.txt", 30));
root.add(subFolder);
root.display(); // يعرض الكل recursively
console.log(root.getSize()); // 60بدون Composite:
function calculateSize(item): number {
if (item instanceof File) return item.size;
if (item instanceof Folder) {
return item.children.reduce((sum, child) =>
sum + calculateSize(child), 0
);
}
}كود متكرر في كل عملية.
- Uniform Interface: نفس الواجهة للـ individual و composite
- Tree Structures: سهل بناء أشجار معقدة
- Recursive Operations: العمليات تشتغل recursive بشكل طبيعي
استخدم Composite لما عندك tree structure وتريد معاملة العقد بنفس الطريقة.
classDiagram
class Component {
<<interface>>
+getName() string
+getSize() number
+display() void
}
class File {
-name: string
-size: number
+getName() string
+getSize() number
+display() void
}
class Folder {
-name: string
-items: Component[]
+add(item: Component) void
+getName() string
+getSize() number
+display() void
}
Component <|.. File
Component <|.. Folder
Folder --> Component