From harness-claude
Wraps incompatible interfaces (Object Adapter via composition, async/promise adaptation, two-way adaptation) to make them work together without modifying source code. Useful when integrating third-party libraries or legacy components.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:gof-adapter-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Wrap incompatible interfaces to make them work together without modifying source code.
Wrap incompatible interfaces to make them work together without modifying source code.
Object adapter (composition — preferred in TypeScript):
// What your system expects
interface Logger {
info(message: string, context?: object): void;
error(message: string, error?: Error): void;
warn(message: string, context?: object): void;
}
// What you have (third-party SDK, fixed interface)
class PinoLogger {
log(level: 'info' | 'warn' | 'error', payload: { msg: string; [key: string]: unknown }): void {
console.log(JSON.stringify({ level, ...payload }));
}
}
// Adapter wraps PinoLogger to satisfy Logger interface
class PinoLoggerAdapter implements Logger {
constructor(private readonly pino: PinoLogger) {}
info(message: string, context?: object): void {
this.pino.log('info', { msg: message, ...context });
}
error(message: string, error?: Error): void {
this.pino.log('error', {
msg: message,
err: error ? { message: error.message, stack: error.stack } : undefined,
});
}
warn(message: string, context?: object): void {
this.pino.log('warn', { msg: message, ...context });
}
}
// Usage — client depends only on Logger interface
const logger: Logger = new PinoLoggerAdapter(new PinoLogger());
logger.info('Server started', { port: 3000 });
Adapting an async legacy API:
// Legacy callback-based interface
interface LegacyStorage {
readFile(path: string, callback: (err: Error | null, data: Buffer) => void): void;
writeFile(path: string, data: Buffer, callback: (err: Error | null) => void): void;
}
// Modern promise-based interface expected by new code
interface AsyncStorage {
read(path: string): Promise<Buffer>;
write(path: string, data: Buffer): Promise<void>;
}
class LegacyStorageAdapter implements AsyncStorage {
constructor(private readonly legacy: LegacyStorage) {}
read(path: string): Promise<Buffer> {
return new Promise((resolve, reject) => {
this.legacy.readFile(path, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
write(path: string, data: Buffer): Promise<void> {
return new Promise((resolve, reject) => {
this.legacy.writeFile(path, data, (err) => {
if (err) reject(err);
else resolve();
});
});
}
}
Two-way adapter (adapt in both directions):
// When you need to satisfy two incompatible interfaces simultaneously
class BidirectionalAdapter implements InterfaceA, InterfaceB {
constructor(
private readonly a: ComponentA,
private readonly b: ComponentB
) {}
// InterfaceA methods delegate to ComponentA
doSomethingA(): void {
this.a.operationA();
}
// InterfaceB methods delegate to ComponentB
doSomethingB(): void {
this.b.operationB();
}
}
Adapter vs. Facade: Both simplify usage, but serve different purposes. An Adapter makes one interface compatible with another — the client expects a specific interface. A Facade simplifies a complex subsystem — the client doesn't care about the interface, just wants it simpler. If you're translating interfaces, use Adapter. If you're hiding complexity, use Facade.
Adapter vs. Decorator: Both wrap an object. An Adapter changes the interface. A Decorator adds behavior while keeping the same interface.
Anti-patterns:
Testing with adapters: Mock the target interface, not the adaptee. This is exactly the value of the pattern — tests use the interface, not the concrete third-party dependency.
// In tests, use a mock Logger instead of PinoLoggerAdapter
const mockLogger: Logger = {
info: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
};
refactoring.guru/design-patterns/adapter
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeConverts incompatible class interfaces so they work together, wrapping legacy or third-party code without modifying it. Useful when integrating code with mismatched APIs.
Guides implementation of the Adapter pattern to integrate incompatible interfaces, such as legacy APIs or third-party libraries, by wrapping them with a translation layer.
Generates Adapter pattern for PHP 8.4 to convert incompatible interfaces, wrap legacy code or external libraries like Stripe/AWS SDKs. Includes target interfaces, adapters, and unit tests.