Files
freemo d9e5668cec fix(skills): comprehensive final audit pass for programming-patterns skill
Fixes and improvements from exhaustive audit:

Consistency fixes in SKILL.md:
- 'Pipe & Filter' → 'Pipe and Filter' (one stray '&' found and corrected)
- 'Singleton for factory instance' → clarified to 'register factory as
  singleton-scoped via DI container' (less misleading wording)
- Documentation Format section updated with note that SKILL.md itself is the
  authoritative source for related-pattern combinations

Coverage fix — Related Patterns sections:
- Added '## Related Patterns' to ALL 94 pattern files (was 0/94)
- Each section lists 3–6 related patterns with relationship descriptions
- Covers: why they're related, when to prefer one vs the other,
  and which are often confused

SOLID principles → Creational → Structural → Behavioral → Architectural →
Concurrency → Functional → Resilience → Data Access → Messaging →
Testing → Error Handling → Microservice — all 13 categories covered

Code verification:
- Python: 0 failures (all 85 testable blocks pass)
- Go: 0 failures (all 76 testable blocks pass)
- JavaScript: 0 failures (all 78 testable blocks pass)
- All 239 code blocks verified correct after edits

Final skill state:
- 108 files, 36,524 lines across 13 reference categories
- 94/94 pattern files have Related Patterns sections
- 2,815-line SKILL.md with 67 decision trees, 23 scenarios,
  0 broken references, 0 naming inconsistencies
2026-04-15 13:22:13 -04:00

5.9 KiB

Adapter Pattern

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

Problem

You have a LegacyPrinter with a print_old(text) method, but your application expects a Printer interface with a print(text) method. You cannot modify the legacy code.

Solution

Create an Adapter class that implements the target Printer interface and internally delegates to the LegacyPrinter's incompatible method.

┌────────┐       ┌─────────────────┐       ┌───────────────┐
│ Client  │──────▶│  Printer (intf) │       │ LegacyPrinter │
│         │       │  + print(text)  │       │ + print_old() │
└────────┘       └─────────────────┘       └───────────────┘
                          ▲                        ▲
                          │                        │
                 ┌────────┴────────┐               │
                 │ PrinterAdapter   │───────────────┘
                 │ + print(text)    │  delegates to print_old()
                 └─────────────────┘

When to Use

  • You need to use an existing class but its interface doesn't match what you need.
  • You want to create a reusable class that cooperates with unrelated or unforeseen classes.
  • You need to integrate third-party or legacy code without modifying it.

When to Avoid

  • The interfaces are already compatible — just use the object directly.
  • You can modify the source of the incompatible class (refactor instead).
  • The adaptation is so complex that a full rewrite would be simpler.

Pseudocode

interface Printer:
    method print(text)

class LegacyPrinter:
    method print_old(text):
        output "[Legacy] " + text

class PrinterAdapter implements Printer:
    field legacy: LegacyPrinter

    constructor(legacy):
        this.legacy = legacy

    method print(text):
        legacy.print_old(text)

// Usage
legacy = new LegacyPrinter()
adapter = new PrinterAdapter(legacy)
adapter.print("Hello, Adapter!")

Python

from abc import ABC, abstractmethod


class Printer(ABC):
    """Target interface the client expects."""

    @abstractmethod
    def print(self, text: str) -> None: ...


class LegacyPrinter:
    """Existing class with an incompatible interface."""

    def print_old(self, text: str) -> None:
        print(f"[Legacy] {text}")


class PrinterAdapter(Printer):
    """Adapter that wraps LegacyPrinter to satisfy the Printer interface."""

    def __init__(self, legacy: LegacyPrinter) -> None:
        self._legacy = legacy

    def print(self, text: str) -> None:
        self._legacy.print_old(text)


def client_code(printer: Printer) -> None:
    """Client only knows about the Printer interface."""
    printer.print("Hello from the client!")


if __name__ == "__main__":
    legacy = LegacyPrinter()
    adapter = PrinterAdapter(legacy)

    print("--- Direct legacy call ---")
    legacy.print_old("direct call")

    print("\n--- Through adapter ---")
    client_code(adapter)

Output:

--- Direct legacy call ---
[Legacy] direct call

--- Through adapter ---
[Legacy] Hello from the client!

Go

package main

import "fmt"

// Target interface the client expects.
type Printer interface {
	Print(text string)
}

// LegacyPrinter has an incompatible method name.
type LegacyPrinter struct{}

func (lp *LegacyPrinter) PrintOld(text string) {
	fmt.Printf("[Legacy] %s\n", text)
}

// PrinterAdapter adapts LegacyPrinter to the Printer interface.
type PrinterAdapter struct {
	legacy *LegacyPrinter
}

func NewPrinterAdapter(legacy *LegacyPrinter) *PrinterAdapter {
	return &PrinterAdapter{legacy: legacy}
}

func (a *PrinterAdapter) Print(text string) {
	a.legacy.PrintOld(text)
}

// clientCode only depends on the Printer interface.
func clientCode(p Printer) {
	p.Print("Hello from the client!")
}

func main() {
	legacy := &LegacyPrinter{}
	adapter := NewPrinterAdapter(legacy)

	fmt.Println("--- Direct legacy call ---")
	legacy.PrintOld("direct call")

	fmt.Println("\n--- Through adapter ---")
	clientCode(adapter)
}

Output:

--- Direct legacy call ---
[Legacy] direct call

--- Through adapter ---
[Legacy] Hello from the client!

JavaScript

// Target interface expectation: object with print(text)

class LegacyPrinter {
  printOld(text) {
    console.log(`[Legacy] ${text}`);
  }
}

class PrinterAdapter {
  constructor(legacyPrinter) {
    this._legacy = legacyPrinter;
  }

  print(text) {
    this._legacy.printOld(text);
  }
}

function clientCode(printer) {
  printer.print("Hello from the client!");
}

// --- Main ---
const legacy = new LegacyPrinter();
const adapter = new PrinterAdapter(legacy);

console.log("--- Direct legacy call ---");
legacy.printOld("direct call");

console.log("\n--- Through adapter ---");
clientCode(adapter);

Output:

--- Direct legacy call ---
[Legacy] direct call

--- Through adapter ---
[Legacy] Hello from the client!
  • Facade — Adapter translates one interface; Facade simplifies a complex subsystem. An Adapter for a complex system can look like a Facade.
  • Decorator — Decorator adds behavior while preserving interface; Adapter changes the interface without adding behavior.
  • Proxy — Proxy preserves the interface and controls access; Adapter changes the interface.
  • Bridge — Adapter reconciles existing incompatible interfaces; Bridge separates abstraction from implementation from the start.
  • Strangler Fig — Adapter is the key tool in Strangler Fig migration: the new interface is an Adapter over the old one.