← Back to PatternPip

ADAPTER / PRACTICE

One player.
Different library languages.

You met Adapter through weather data. Now connect an older audio library to an existing player.

YOUR BRIEF

The music fits. The interface does not.

The player calls load(id) and expects a title, a duration in seconds and a playable boolean. LegacyAudio only offers findTrack(id), returning track_name, length_ms and access_code.

The library cannot be passed directly to the player. Preserve its data's meaning while making it fit the player's contract. Unknown codes must cause an error rather than an invented permission.

The player already has a contract

type Track = Readonly<{ title: string;
  durationSeconds: number; playable: boolean }>;
interface TrackSource { load(id: string): Track }
function readPlayer(source: TrackSource, id: string): Track {
  return source.load(id);
}

Keep this client unaware of vendor-specific units, method names and access codes.

01 / ASSEMBLE

Translate at the boundary.

Choose where the vendor rules belong, then preserve the meaning of its duration and access fields.

Your assembled code

TypeScript preview. Highlighting follows the selected execution.

Target · what the player understands

type Track = Readonly<{ title: string; durationSeconds: number; playable: boolean }>;
interface TrackSource { load(id: string): Track }

Existing library · incompatible method and data

type LegacyTrack = Readonly<{ track_name: string; length_ms: number; access_code: string }>;
class LegacyAudio {
  constructor(private id: string, private track: LegacyTrack) {}
  findTrack(id: string): LegacyTrack {
    if (id !== this.id) throw new Error("Track not found");
    return this.track;
  }
}

Your translation boundary

// Choose all three pieces to assemble the translation.

Player · target interface

function readPlayer(source: TrackSource, id: string): Track { return source.load(id); }

Setup · supply the selected source

// Complete the assembly before loading a track.

02 / RUN & OBSERVE

Same track. A different interface.

185000 milliseconds and ok should become 185 seconds and playable = true.

Request goes down ↓ · Translated data returns up ↑

Player · the clientsource.load("track-01")Expects title, durationSeconds and playable

No track loaded yet

LegacyAudioAdapterImplements TrackSource · wraps the existing libraryload(id) → findTrack(id)

Method, fields, units and code meanings meet here.

LegacyAudio · existing serviceSample vendor response · unchanged
{
  "track_name": "Evening loop",
  "length_ms": 185000,
  "access_code": "ok"
}

Choose an assembly, then watch the request and response cross the interface boundary.

Data and design feedback will appear here.

  • ○ Load a playable track — run to verify
  • ○ Load a blocked track — run to verify
  • ○ Reject an unknown access code — run to verify

Each test uses a fresh local library. No audio plays and no external service is contacted. For these known sample shapes, the adapter preserves titles and IDs, converts units, maps known codes and rejects unsupported ones.

03 / TRANSFER THE IDEA

Another library wants to connect.

ArchiveAudio exposes fetch(id) and returns name, duration_seconds and can_play. Its values already use seconds and a boolean; its method and field names still do not fit TrackSource.

Connect it while keeping the same player. Which edits are needed?

First pass all three legacy-library cases with the same assembly.

Select all required edits

Compare with a complete solution

No timer and no attempt limit. Try another assembly, use a hint, or reveal the answer when it helps.