From harness-claude
Implements Factory Method design pattern in TypeScript with class-based creators, functional switches, and registered generics. Use when object types are runtime-determined, subclasses control instantiation, or to follow Open/Closed Principle.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Define a factory interface that subclasses use to decide which object to instantiate.
Implements GOF Abstract Factory pattern in TypeScript for creating families of related objects via factory interfaces without concrete coupling. Use for swappable UI themes or product suites like DB+cache pairs.
Generates DDD-compliant factories for PHP 8.4 domain objects, encapsulating complex creation logic with input validation and unit tests. Ideal for intricate entity instantiation, aggregates, and reconstruction from persistence.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Define a factory interface that subclasses use to decide which object to instantiate.
Core structure — Creator declares the factory method, ConcreteCreators override it:
// Product interface
interface Notification {
send(message: string): Promise<void>;
}
// Concrete products
class EmailNotification implements Notification {
constructor(private readonly address: string) {}
async send(message: string): Promise<void> {
console.log(`Email to ${this.address}: ${message}`);
}
}
class SMSNotification implements Notification {
constructor(private readonly phone: string) {}
async send(message: string): Promise<void> {
console.log(`SMS to ${this.phone}: ${message}`);
}
}
// Creator — declares the factory method
abstract class NotificationCreator {
// Factory method — subclasses must implement
abstract createNotification(recipient: string): Notification;
// Template method that uses the factory method
async notify(recipient: string, message: string): Promise<void> {
const notification = this.createNotification(recipient);
await notification.send(message);
}
}
// Concrete creators
class EmailNotificationCreator extends NotificationCreator {
createNotification(recipient: string): Notification {
return new EmailNotification(recipient);
}
}
class SMSNotificationCreator extends NotificationCreator {
createNotification(recipient: string): Notification {
return new SMSNotification(recipient);
}
}
// Client code — depends only on Creator, not ConcreteProduct
async function main(creator: NotificationCreator) {
await creator.notify('user@example.com', 'Your order shipped');
}
Function-based factory (TypeScript idiomatic, no classes needed):
type NotificationType = 'email' | 'sms' | 'push';
function createNotification(type: NotificationType, recipient: string): Notification {
switch (type) {
case 'email':
return new EmailNotification(recipient);
case 'sms':
return new SMSNotification(recipient);
case 'push':
return new PushNotification(recipient);
default:
// Exhaustiveness check — TypeScript will error if a case is missing
const _exhaustive: never = type;
throw new Error(`Unknown notification type: ${type}`);
}
}
Generic factory with registration:
type Constructor<T> = new (...args: any[]) => T;
class NotificationFactory {
private static registry = new Map<string, Constructor<Notification>>();
static register(type: string, ctor: Constructor<Notification>): void {
NotificationFactory.registry.set(type, ctor);
}
static create(type: string, ...args: any[]): Notification {
const Ctor = NotificationFactory.registry.get(type);
if (!Ctor) throw new Error(`Unknown notification type: ${type}`);
return new Ctor(...args);
}
}
NotificationFactory.register('email', EmailNotification);
NotificationFactory.register('sms', SMSNotification);
Factory Method vs. Abstract Factory: Factory Method produces one product via subclass override. Abstract Factory produces families of related products via composition. Start with Factory Method; reach for Abstract Factory when you need a suite of related objects.
Open/Closed Principle in action: Adding a new notification type (SlackNotification) means creating a new ConcreteCreator class — no changes to existing creators or the notify() logic.
Anti-patterns:
if/else logic inside a single create() method that grows indefinitely — use a registry insteadnever type catches missing cases at compile timeWhen to skip the pattern:
new User())refactoring.guru/design-patterns/factory-method