design-patterns-implementation
About
This skill helps developers implement common design patterns like Singleton, Factory, and Observer to solve architectural problems. It is best used when refactoring code, building extensible systems, or applying SOLID principles. The skill provides guidance for creating maintainable, testable, and decoupled software architectures.
Documentation
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
Quick Install
/plugin add https://github.com/aj-geddes/useful-ai-prompts/tree/main/design-patterns-implementationCopy and paste this command in Claude Code to install this skill
GitHub 仓库
Related Skills
langchain
MetaLangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.
Algorithmic Art Generation
MetaThis skill helps developers create algorithmic art using p5.js, focusing on generative art, computational aesthetics, and interactive visualizations. It automatically activates for topics like "generative art" or "p5.js visualization" and guides you through creating unique algorithms with features like seeded randomness, flow fields, and particle systems. Use it when you need to build reproducible, code-driven artistic patterns.
webapp-testing
TestingThis Claude Skill provides a Playwright-based toolkit for testing local web applications through Python scripts. It enables frontend verification, UI debugging, screenshot capture, and log viewing while managing server lifecycles. Use it for browser automation tasks but run scripts directly rather than reading their source code to avoid context pollution.
finishing-a-development-branch
TestingThis skill helps developers complete finished work by verifying tests pass and then presenting structured integration options. It guides the workflow for merging, creating PRs, or cleaning up branches after implementation is done. Use it when your code is ready and tested to systematically finalize the development process.
