スキル一覧に戻る
Dsantiagomj

patterns

by Dsantiagomj

0🍴 0📅 2026年1月19日
GitHubで見るManusで実行

SKILL.md


name: patterns domain: software-design description: > Software design patterns, SOLID principles, and architectural best practices. Covers creational, structural, and behavioral patterns, anti-patterns to avoid, and when to apply each pattern. Trigger: When architecting systems, when refactoring code, when implementing design patterns, when applying SOLID principles, when identifying anti-patterns. version: 1.0.0 tags: [design-patterns, SOLID, architecture, best-practices, anti-patterns] metadata: version: "1.0" last_updated: "2026-01-17" category: domain progressive_disclosure: true references:

  • name: Design Patterns Guide url: ./references/design-patterns.md type: local
  • name: SOLID Principles url: ./references/solid-principles.md type: local
  • name: Refactoring.Guru - Design Patterns url: https://refactoring.guru/design-patterns type: documentation
  • name: Refactoring.Guru - SOLID Principles url: https://refactoring.guru/solid type: documentation

Patterns - Software Design & Architecture

Know when to use (and when NOT to use) design patterns


When to Use This Skill

Use this skill when:

  • Architecting new systems or refactoring existing ones
  • Identifying code smells and anti-patterns
  • Choosing appropriate design patterns for specific problems
  • Applying SOLID principles to improve code quality
  • Making code more testable, maintainable, and extensible

Don't use this skill when:

  • Simple, straightforward code is sufficient
  • Premature optimization or abstraction would add complexity
  • The problem doesn't warrant pattern application

Critical Patterns

Pattern 1: SOLID Principles

When: Designing maintainable, testable code

Single Responsibility Principle (SRP):

// ✅ Good: Each class has one responsibility
class UserRepository {
  save(user: User) { /* DB logic */ }
}

class EmailService {
  sendWelcomeEmail(user: User) { /* Email logic */ }
}

class UserReportGenerator {
  generate(user: User) { /* Report logic */ }
}

// ❌ Bad: God class doing everything
class UserService {
  saveUser(user: User) { /* ... */ }
  sendEmail(user: User) { /* ... */ }
  generateReport(user: User) { /* ... */ }
}

Dependency Inversion Principle (DIP):

// ✅ Good: Depend on abstractions
interface MessageSender {
  send(message: string): void;
}

class EmailService implements MessageSender {
  send(message: string) { /* SMTP logic */ }
}

class UserRegistration {
  constructor(private messageSender: MessageSender) {}

  register(user: User) {
    this.messageSender.send(`Welcome ${user.name}`);
  }
}

// ❌ Bad: Tight coupling to concrete class
class UserRegistration {
  private emailService = new EmailService();

  register(user: User) {
    this.emailService.send(`Welcome ${user.name}`);
  }
}

Why: SOLID principles create code that's easier to test, maintain, and extend. They prevent common pitfalls like tight coupling and god classes.

For complete SOLID deep dive: SOLID Principles Reference


Pattern 2: Factory Pattern

When: Creating objects with complex initialization or multiple variants

Good:

interface Button {
  render(): void;
}

class WindowsButton implements Button {
  render() { console.log('Render Windows button'); }
}

class MacButton implements Button {
  render() { console.log('Render Mac button'); }
}

class ButtonFactory {
  static create(os: 'windows' | 'mac'): Button {
    switch (os) {
      case 'windows': return new WindowsButton();
      case 'mac': return new MacButton();
      default: throw new Error('Unknown OS');
    }
  }
}

// Usage
const button = ButtonFactory.create('windows');
button.render();

When to use:

  • Object creation is complex or varies by context
  • Need to decouple object creation from usage
  • Creating families of related objects

When NOT to use:

  • Simple object creation (just use new)
  • Only one type of object exists

Pattern 3: Strategy Pattern

When: Swapping algorithms or behaviors at runtime

Good:

interface PaymentStrategy {
  pay(amount: number): void;
}

class CreditCardPayment implements PaymentStrategy {
  pay(amount: number) {
    console.log(`Paid $${amount} with credit card`);
  }
}

class PayPalPayment implements PaymentStrategy {
  pay(amount: number) {
    console.log(`Paid $${amount} with PayPal`);
  }
}

class ShoppingCart {
  constructor(private paymentStrategy: PaymentStrategy) {}

  checkout(amount: number) {
    this.paymentStrategy.pay(amount);
  }
}

// Usage
const cart = new ShoppingCart(new CreditCardPayment());
cart.checkout(100);

Bad:

// ❌ Multiple if/else statements
class ShoppingCart {
  checkout(amount: number, paymentType: string) {
    if (paymentType === 'creditCard') {
      // Process credit card
    } else if (paymentType === 'paypal') {
      // Process PayPal
    } else if (paymentType === 'crypto') {
      // Process crypto
    }
  }
}

Why: Strategy pattern eliminates conditional logic and makes adding new payment methods easy without modifying existing code (Open/Closed Principle).


Pattern 4: Observer Pattern

When: Implementing event-driven systems or pub/sub

Good:

interface Observer {
  update(data: any): void;
}

class Subject {
  private observers: Observer[] = [];

  subscribe(observer: Observer) {
    this.observers.push(observer);
  }

  notify(data: any) {
    this.observers.forEach(observer => observer.update(data));
  }
}

class EmailSubscriber implements Observer {
  update(data: any) {
    console.log(`Email sent: ${data}`);
  }
}

class SMSSubscriber implements Observer {
  update(data: any) {
    console.log(`SMS sent: ${data}`);
  }
}

// Usage
const newsletter = new Subject();
newsletter.subscribe(new EmailSubscriber());
newsletter.subscribe(new SMSSubscriber());
newsletter.notify('New article published!');

When to use:

  • One-to-many dependencies
  • Event systems
  • State synchronization across components

Pattern 5: Adapter Pattern

When: Integrating incompatible interfaces

Good:

// Legacy interface
class OldPaymentGateway {
  processPayment(amount: number) {
    console.log(`Old gateway: $${amount}`);
  }
}

// New interface
interface PaymentProcessor {
  pay(amount: number, currency: string): void;
}

// Adapter
class PaymentAdapter implements PaymentProcessor {
  constructor(private oldGateway: OldPaymentGateway) {}

  pay(amount: number, currency: string) {
    if (currency !== 'USD') {
      throw new Error('Old gateway only supports USD');
    }
    this.oldGateway.processPayment(amount);
  }
}

When to use:

  • Integrating third-party libraries
  • Working with legacy code
  • Reusing existing classes with different interfaces

Anti-Patterns

❌ Anti-Pattern 1: Premature Abstraction

Don't do this:

// ❌ Over-engineered for simple config
interface ConfigStrategy { get(key: string): any; }
class JSONConfigStrategy implements ConfigStrategy { /* ... */ }
class YAMLConfigStrategy implements ConfigStrategy { /* ... */ }
class ConfigFactory { /* ... */ }

Do this instead:

// ✅ Start simple
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
};

Why: YAGNI (You Aren't Gonna Need It). Add abstraction when you have a concrete need, not "just in case."


❌ Anti-Pattern 2: God Object

Don't do this:

// ❌ One class doing everything
class Application {
  handleAuth() { /* ... */ }
  renderUI() { /* ... */ }
  saveToDatabase() { /* ... */ }
  sendEmail() { /* ... */ }
  generateReports() { /* ... */ }
  // 50 more methods...
}

Do this instead:

// ✅ Apply Single Responsibility Principle
class AuthService { /* ... */ }
class UIRenderer { /* ... */ }
class DatabaseService { /* ... */ }
class EmailService { /* ... */ }
class ReportGenerator { /* ... */ }

❌ Anti-Pattern 3: Copy-Paste Programming

Don't do this:

// ❌ Duplicated code
function validateEmail(email: string) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function validateUserEmail(user: User) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(user.email);
}

Do this instead:

// ✅ DRY (Don't Repeat Yourself)
function isValidEmail(email: string) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function validateUserEmail(user: User) {
  return isValidEmail(user.email);
}

Code Examples

Example 1: Factory Pattern for Payment Processing

interface PaymentProcessor {
  process(amount: number): Promise<void>;
}

class StripeProcessor implements PaymentProcessor {
  async process(amount: number) {
    console.log(`Processing $${amount} via Stripe`);
  }
}

class PayPalProcessor implements PaymentProcessor {
  async process(amount: number) {
    console.log(`Processing $${amount} via PayPal`);
  }
}

class PaymentFactory {
  static create(provider: 'stripe' | 'paypal'): PaymentProcessor {
    switch (provider) {
      case 'stripe': return new StripeProcessor();
      case 'paypal': return new PayPalProcessor();
    }
  }
}

// Usage
const processor = PaymentFactory.create('stripe');
await processor.process(99.99);

Example 2: Dependency Injection for Testability

interface Logger {
  log(message: string): void;
}

class UserService {
  constructor(private logger: Logger) {}

  createUser(name: string) {
    this.logger.log(`Creating user: ${name}`);
    // User creation logic
  }
}

// Production
const service = new UserService(new ConsoleLogger());

// Testing
const mockLogger = { log: jest.fn() };
const testService = new UserService(mockLogger);

For comprehensive examples and detailed implementations, see the references/ folder.


Quick Reference

When to Use Each Pattern

PatternUse WhenDon't Use When
FactoryComplex object creation, multiple variantsSimple new is sufficient
BuilderMany optional parametersFew parameters, simple construction
SingletonTruly need ONE global instanceJust want convenience (use DI)
AdapterIntegrating incompatible interfacesInterfaces already compatible
DecoratorAdding responsibilities dynamicallyStatic behavior is fine
FacadeSimplifying complex subsystemSubsystem is already simple
ObserverEvent-driven, one-to-many updatesSimple callbacks work
StrategySwappable algorithms at runtimeFixed algorithm
CommandUndo/redo, queuing operationsDirect method calls work

SOLID Quick Checklist

  • S: Each class has single, focused responsibility
  • O: New features added via extension, not modification
  • L: Subtypes don't break parent class behavior
  • I: Interfaces are small and focused
  • D: Depend on abstractions, inject dependencies

Progressive Disclosure

For detailed implementations and examples:

  • Design Patterns Guide - Complete pattern implementations (Factory, Builder, Singleton, Adapter, Decorator, Facade, Observer, Strategy, Command)
  • SOLID Principles - Deep dive into SRP, OCP, LSP, ISP, DIP with real-world examples

References


Maintained by dsmj-ai-toolkit

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です