Lab
Null object
// What the rider's phone played. Checker plumbing: you don't need to edit this.
const felt: string[] = [];
// The phone's vibration, behind one method.
interface Haptics {
pulse(cue: string): void;
}
// The phone's vibration motor.
class PhoneHaptics implements Haptics {
pulse(cue: string): void {
felt.push(cue);
}
}
// The dock is required: it releases or locks a bike, or throws why it can't.
class MemoryDock {
private docked: Set<string>;
constructor(bikes: string[]) {
this.docked = new Set(bikes);
}
release(bike: string): void {
if (!this.docked.has(bike)) throw new Error(`${bike} is not at this dock`);
this.docked.delete(bike);
}
lock(bike: string): void {
if (this.docked.has(bike)) throw new Error(`${bike} is already docked`);
this.docked.add(bike);
}
}
// Not written yet: every rider gets the phone's vibration, even with haptics off.
function chooseHaptics(hapticsOn: boolean): Haptics {
return new PhoneHaptics();
}
class RideFlow {
private dock: MemoryDock;
private phone: PhoneHaptics;
private hapticsOn: boolean;
constructor(dock: MemoryDock, phone: PhoneHaptics, hapticsOn: boolean) {
this.dock = dock;
this.phone = phone;
this.hapticsOn = hapticsOn;
}
unlock(bike: string): string {
if (bike === '') return 'failed: no bike id';
try {
this.dock.release(bike);
} catch (error) {
return `failed: ${(error as Error).message}`;
}
if (this.hapticsOn) this.phone.pulse('unlocked');
return `unlocked ${bike}`;
}
// Added later, for the end of a ride.
endRide(bike: string): string {
try {
this.dock.lock(bike);
} catch (error) {
return `failed: ${(error as Error).message}`;
}
this.phone.pulse('locked');
return `locked ${bike}`;
}
}
// The app's boundary: where the rider's setting reaches the flow.
function startRideFlow(dock: MemoryDock, hapticsOn: boolean): RideFlow {
return new RideFlow(dock, new PhoneHaptics(), hapticsOn);
}
// The platform team's dock-arrival nudge: it pulses whatever Haptics the
// app hands it, without asking.
function nearbyNudge(haptics: Haptics): string {
haptics.pulse('nearby');
return 'nudged';
}