Lab
Composite
type Action = 'pause' | 'resume';
// What a valve and a zone have in common: one command.
interface IrrigationPart {
readonly id: string;
command(action: Action, trace: string[]): void;
}
class Valve implements IrrigationPart {
paused = false;
constructor(readonly id: string) {}
command(action: Action, trace: string[]): void {
trace.push(this.id);
this.paused = action === 'pause';
}
}
class Zone implements IrrigationPart {
constructor(readonly id: string, readonly children: IrrigationPart[]) {}
command(action: Action, trace: string[]): void {
trace.push(this.id);
for (const child of this.children) child.command(action, trace);
}
}
// The controller: one command to whatever the operator selected.
function send(part: IrrigationPart, action: Action): string[] {
const trace: string[] = [];
part.command(action, trace);
return trace;
}
const nursery = new Zone('nursery', [new Valve('propagation-valve')]);
const west = new Zone('west', [new Valve('east-valve'), nursery]);
const house = new Zone('house-1', [new Valve('north-valve'), west]);
const bench = new Valve('bench-valve'); // the potting bench, in no zone
// A leak report pauses the whole house; maintenance pauses one valve.
const leak = send(house, 'pause');
const maintenance = send(bench, 'pause');
console.log(`leak: ${leak.join(' > ')}`);
console.log(`maintenance: ${maintenance.join(' > ')}`);
TODO
Visual to come