Aller au contenu principal

Pattern Bridge

Séparez ce que quelque chose fait de comment il le fait, pour que les deux puissent évoluer indépendamment.


Le Problème

Vous avez des sources audio (Ode To The Winners, The Epic Hero, Gaia) et des visualiseurs (Nebula, Silk, Smear, Cosmos). Sans Bridge, il faudrait OdeNebula, OdeSilk, OdeSmear, EpicNebula... une explosion de classes.

interface AudioSource {
getFrame(time: number): number[];
}

interface Visualizer {
render(frame: number[]): void;
}

abstract class MusicPlayer {
constructor(
protected source: AudioSource,
protected visualizer: Visualizer,
) {}
abstract play(): void;
}

class LivePlayer extends MusicPlayer {
play() {
const frame = this.source.getFrame(Date.now());
this.visualizer.render(frame);
}
}

Deux hiérarchies, une classe abstraite, et des sous-classes concrètes. Tout ça pour combiner deux choses qui varient indépendamment.


La Solution

Passez la fonction en paramètre. Les deux axes se composent librement.

type AudioFrame = Uint8Array;

type Visualizer = (
ctx: CanvasRenderingContext2D,
frame: AudioFrame,
w: number, h: number,
accent: string, time: number,
) => void;

function visualize(
ctx: CanvasRenderingContext2D,
frame: AudioFrame,
renderer: Visualizer,
w: number, h: number,
accent: string, time: number,
) {
renderer(ctx, frame, w, h, accent, time);
}

// 3 sources × 5 visualiseurs = 15 combinaisons, zéro couplage
visualize(ctx, frame, nebulaVisualizer, w, h, accent, t);
visualize(ctx, frame, silkVisualizer, w, h, accent, t);
visualize(ctx, frame, cosmosVisualizer, w, h, accent, t);

Pas de classes. Pas d'héritage. Juste des fonctions et des données.

Absorbé par le Langage

Cette solution n'utilise pas Pithos. C'est justement le point.

En TypeScript fonctionnel, passer une fonction en paramètre est le pattern Bridge. Eidos exporte une fonction @deprecated createBridge() qui n'existe que pour vous guider ici.


Démo

Choisissez une source audio et un visualiseur. Les deux axes varient indépendamment : 3 sources × 5 visualiseurs = 15 combinaisons, le tout depuis un seul appel visualize(frame, renderer).

Code
/**
* The Bridge function.
*
* Two independent axes: AudioSource × Visualizer.
* This function is the bridge — it connects a frame of audio data
* to any renderer, with zero coupling between them.
*/

import type { AudioFrame, Visualizer } from "./types";

export function visualize(
ctx: CanvasRenderingContext2D,
frame: AudioFrame,
renderer: Visualizer,
w: number,
h: number,
accent: string,
time: number,
): void {
renderer(ctx, frame, w, h, accent, time);
}
Result

API

  • createBridge @deprecated — passez simplement des fonctions en paramètres

Liens connexes