Composite Operations and Traversal
Common Operations on Composites
Most composite operations fall into these categories:
Aggregation Operations
typescript1interface ShippingUnit {2 // Aggregation - sum of all children3 getWeight(): number;4 getItemCount(): number;5 getTotalValue(): number;6}78class Container implements ShippingUnit {9 getTotalValue(): number {10 return this.children.reduce(11 (sum, child) => sum + child.getTotalValue(),12 013 );14 }15}1617class Item implements ShippingUnit {18 getTotalValue(): number {19 return this.price;20 }21}
Search Operations
typescript1interface ShippingUnit {2 find(predicate: (unit: ShippingUnit) => boolean): ShippingUnit | undefined;3 findAll(predicate: (unit: ShippingUnit) => boolean): ShippingUnit[];4}56class Container implements ShippingUnit {7 find(predicate: (unit: ShippingUnit) => boolean): ShippingUnit | undefined {8 if (predicate(this)) return this;910 for (const child of this.children) {11 const found = child.find(predicate);12 if (found) return found;13 }14 return undefined;15 }1617 findAll(predicate: (unit: ShippingUnit) => boolean): ShippingUnit[] {18 const results: ShippingUnit[] = [];19 if (predicate(this)) results.push(this);2021 for (const child of this.children) {22 results.push(...child.findAll(predicate));23 }24 return results;25 }26}2728// Usage29const fragileItems = order.findAll(unit =>30 unit instanceof Item && unit.isFragile31);
Validation Operations
typescript1interface ShippingUnit {2 validate(): ValidationResult;3}45class Container implements ShippingUnit {6 validate(): ValidationResult {7 const errors: string[] = [];89 // Container-level validation10 if (this.getWeight() > this.maxWeight) {11 errors.push(`Container exceeds max weight of ${this.maxWeight}kg`);12 }1314 // Validate all children15 for (const child of this.children) {16 const childResult = child.validate();17 errors.push(...childResult.errors);18 }1920 return {21 isValid: errors.length === 0,22 errors23 };24 }25}
Traversal Strategies
Depth-First (Default)
typescript1class Container {2 // Pre-order: visit node before children3 traversePreOrder(callback: (unit: ShippingUnit) => void): void {4 callback(this);5 for (const child of this.children) {6 if (child instanceof Container) {7 child.traversePreOrder(callback);8 } else {9 callback(child);10 }11 }12 }1314 // Post-order: visit node after children15 traversePostOrder(callback: (unit: ShippingUnit) => void): void {16 for (const child of this.children) {17 if (child instanceof Container) {18 child.traversePostOrder(callback);19 } else {20 callback(child);21 }22 }23 callback(this);24 }25}
Breadth-First
typescript1function traverseBreadthFirst(2 root: ShippingUnit,3 callback: (unit: ShippingUnit, depth: number) => void4): void {5 const queue: Array<{ unit: ShippingUnit; depth: number }> = [6 { unit: root, depth: 0 }7 ];89 while (queue.length > 0) {10 const { unit, depth } = queue.shift()!;11 callback(unit, depth);1213 if (unit instanceof Container) {14 for (const child of unit.getChildren()) {15 queue.push({ unit: child, depth: depth + 1 });16 }17 }18 }19}2021// Usage: print level by level22traverseBreadthFirst(order, (unit, depth) => {23 console.log(`Level ${depth}: ${unit.id || unit.sku}`);24});
Path Operations
typescript1interface ShippingUnit {2 getPath(): string[];3 findPath(target: ShippingUnit): string[] | null;4}56class Container implements ShippingUnit {7 findPath(8 target: ShippingUnit,9 currentPath: string[] = []10 ): string[] | null {11 const path = [...currentPath, this.id];1213 if (this === target) return path;1415 for (const child of this.children) {16 if (child === target) {17 return [...path, child instanceof Item ? child.sku : child.id];18 }1920 if (child instanceof Container) {21 const found = child.findPath(target, path);22 if (found) return found;23 }24 }2526 return null;27 }28}2930// Usage31const item = order.find(u => u instanceof Item && u.sku === 'LAPTOP-001');32const path = order.findPath(item);33// ['ORDER-123', 'BOX-medium', 'LAPTOP-001']
Cloning Composites
typescript1interface ShippingUnit {2 clone(): ShippingUnit;3}45class Container implements ShippingUnit {6 clone(): Container {7 const cloned = new Container(8 this.id + '-copy',9 this.containerWeight,10 { ...this.containerDimensions }11 );1213 for (const child of this.children) {14 cloned.add(child.clone());15 }1617 return cloned;18 }19}2021class Item implements ShippingUnit {22 clone(): Item {23 return new Item(24 this.sku,25 this.weight,26 { ...this.dimensions }27 );28 }29}
Composite with Visitor
typescript1interface ShippingVisitor {2 visitItem(item: Item): void;3 visitBox(box: Box): void;4 visitPallet(pallet: Pallet): void;5}67class WeightCalculator implements ShippingVisitor {8 private totalWeight = 0;910 visitItem(item: Item): void {11 this.totalWeight += item.getWeight();12 }1314 visitBox(box: Box): void {15 this.totalWeight += box.getBoxWeight();16 }1718 visitPallet(pallet: Pallet): void {19 this.totalWeight += pallet.getPalletWeight();20 }2122 getTotal(): number {23 return this.totalWeight;24 }25}2627// Composite accepts visitor28class Container {29 accept(visitor: ShippingVisitor): void {30 visitor.visitBox(this);31 for (const child of this.children) {32 child.accept(visitor);33 }34 }35}
Summary
| Operation Type | Use Case |
|---|---|
| Aggregation | Totals, counts, sums |
| Search | Find items matching criteria |
| Validation | Check constraints at all levels |
| Traversal | Process all nodes in order |
| Path | Locate items in hierarchy |
| Clone | Deep copy entire structure |
Composite's power comes from applying operations recursively across the entire tree structure.