Claude-skill-registry design-patterns-implementation
Apply appropriate design patterns (Singleton, Factory, Observer, Strategy, etc.) to solve architectural problems. Use when refactoring code architecture, implementing extensible systems, or following SOLID principles.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/design-patterns-implementation" ~/.claude/skills/majiayu000-claude-skill-registry-design-patterns-implementation && rm -rf "$T"
manifest:
skills/data/design-patterns-implementation/SKILL.mdsource content
Design Patterns Implementation
Overview
Apply proven design patterns to create maintainable, extensible, and testable code architectures.
When to Use
- Solving common architectural problems
- Making code more maintainable and testable
- Implementing extensible plugin systems
- Decoupling components
- Following SOLID principles
- Code reviews identifying architectural issues
Common Design Patterns
1. Singleton Pattern
Ensure a class has only one instance with global access.
class DatabaseConnection { private static instance: DatabaseConnection; private connection: any; private constructor() { this.connection = this.createConnection(); } public static getInstance(): DatabaseConnection { if (!DatabaseConnection.instance) { DatabaseConnection.instance = new DatabaseConnection(); } return DatabaseConnection.instance; } private createConnection() { return { /* connection logic */ }; } } // Usage const db1 = DatabaseConnection.getInstance(); const db2 = DatabaseConnection.getInstance(); // db1 === db2 (same instance)
2. Factory Pattern
Create objects without specifying exact classes.
from abc import ABC, abstractmethod class PaymentProcessor(ABC): @abstractmethod def process_payment(self, amount: float) -> bool: pass class StripeProcessor(PaymentProcessor): def process_payment(self, amount: float) -> bool: # Stripe-specific logic return True class PayPalProcessor(PaymentProcessor): def process_payment(self, amount: float) -> bool: # PayPal-specific logic return True class PaymentProcessorFactory: @staticmethod def create_processor(processor_type: str) -> PaymentProcessor: if processor_type == 'stripe': return StripeProcessor() elif processor_type == 'paypal': return PayPalProcessor() else: raise ValueError(f'Unknown processor: {processor_type}') # Usage processor = PaymentProcessorFactory.create_processor('stripe') processor.process_payment(100.00)
3. Observer Pattern
Define one-to-many dependency for event notification.
class Subject { constructor() { this.observers = []; } attach(observer) { this.observers.push(observer); } detach(observer) { this.observers = this.observers.filter(obs => obs !== observer); } notify(data) { this.observers.forEach(observer => observer.update(data)); } } class Observer { update(data) { console.log('Received update:', data); } } // Usage const subject = new Subject(); const observer1 = new Observer(); const observer2 = new Observer(); subject.attach(observer1); subject.attach(observer2); subject.notify({ event: 'data_changed' });
4. Strategy Pattern
Define family of algorithms and make them interchangeable.
interface CompressionStrategy { byte[] compress(byte[] data); } class ZipCompression implements CompressionStrategy { public byte[] compress(byte[] data) { // ZIP compression logic return data; } } class GzipCompression implements CompressionStrategy { public byte[] compress(byte[] data) { // GZIP compression logic return data; } } class FileCompressor { private CompressionStrategy strategy; public FileCompressor(CompressionStrategy strategy) { this.strategy = strategy; } public void setStrategy(CompressionStrategy strategy) { this.strategy = strategy; } public byte[] compressFile(byte[] data) { return strategy.compress(data); } } // Usage FileCompressor compressor = new FileCompressor(new ZipCompression()); compressor.compressFile(fileData); // Change strategy at runtime compressor.setStrategy(new GzipCompression()); compressor.compressFile(fileData);
5. Decorator Pattern
Add responsibilities to objects dynamically.
interface Coffee { cost(): number; description(): string; } class SimpleCoffee implements Coffee { cost(): number { return 5; } description(): string { return 'Simple coffee'; } } class MilkDecorator implements Coffee { constructor(private coffee: Coffee) {} cost(): number { return this.coffee.cost() + 2; } description(): string { return this.coffee.description() + ', milk'; } } class SugarDecorator implements Coffee { constructor(private coffee: Coffee) {} cost(): number { return this.coffee.cost() + 1; } description(): string { return this.coffee.description() + ', sugar'; } } // Usage let coffee: Coffee = new SimpleCoffee(); console.log(coffee.cost()); // 5 coffee = new MilkDecorator(coffee); console.log(coffee.cost()); // 7 coffee = new SugarDecorator(coffee); console.log(coffee.cost()); // 8 console.log(coffee.description()); // "Simple coffee, milk, sugar"
6. Repository Pattern
Abstract data access logic.
from abc import ABC, abstractmethod from typing import List, Optional class UserRepository(ABC): @abstractmethod def find_by_id(self, user_id: int) -> Optional[User]: pass @abstractmethod def find_all(self) -> List[User]: pass @abstractmethod def save(self, user: User) -> User: pass @abstractmethod def delete(self, user_id: int) -> bool: pass class DatabaseUserRepository(UserRepository): def __init__(self, db_connection): self.db = db_connection def find_by_id(self, user_id: int) -> Optional[User]: result = self.db.query('SELECT * FROM users WHERE id = ?', user_id) return User.from_dict(result) if result else None def find_all(self) -> List[User]: results = self.db.query('SELECT * FROM users') return [User.from_dict(r) for r in results] def save(self, user: User) -> User: self.db.execute('INSERT INTO users (...) VALUES (...)', user.to_dict()) return user def delete(self, user_id: int) -> bool: return self.db.execute('DELETE FROM users WHERE id = ?', user_id)
7. Dependency Injection
Invert control by injecting dependencies.
// Bad: Hard-coded dependencies class OrderService { private db = new MySQLDatabase(); // Tightly coupled private email = new GmailService(); // Tightly coupled createOrder(order: Order) { this.db.save(order); this.email.send(order.customer_email, 'Order created'); } } // Good: Dependency injection interface Database { save(entity: any): void; } interface EmailService { send(to: string, subject: string): void; } class OrderService { constructor( private db: Database, private email: EmailService ) {} createOrder(order: Order) { this.db.save(order); this.email.send(order.customer_email, 'Order created'); } } // Usage - easy to test with mocks const service = new OrderService( new MySQLDatabase(), new GmailService() ); // Test with mocks const testService = new OrderService( new MockDatabase(), new MockEmailService() );
Best Practices
✅ DO
- Choose patterns that solve actual problems
- Keep patterns simple and understandable
- Document why patterns were chosen
- Consider testability
- Follow SOLID principles
- Use dependency injection
- Prefer composition over inheritance
❌ DON'T
- Apply patterns without understanding them
- Over-engineer simple solutions
- Force patterns where they don't fit
- Create unnecessary abstraction layers
- Ignore team familiarity with patterns
When to Use Each Pattern
| Pattern | Use Case |
|---|---|
| Singleton | Database connections, configuration managers |
| Factory | Creating objects based on runtime conditions |
| Observer | Event systems, pub/sub, reactive programming |
| Strategy | Algorithms that can be swapped at runtime |
| Decorator | Adding features dynamically without inheritance |
| Repository | Abstracting data access from business logic |
| Adapter | Making incompatible interfaces work together |
| Facade | Simplifying complex subsystems |
| Command | Undo/redo, task queuing, macro recording |
Resources
- "Design Patterns" by Gang of Four
- "Head First Design Patterns" by Freeman & Freeman
- refactoring.guru/design-patterns