KeiSeiKit-1.0/skills/architecture-rules/references/patterns.md
Parfii-bot a4e667de10 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

153 lines
6.1 KiB
Markdown

# Design Patterns — When to Use
## Creational
### Factory Method
- **When**: Object creation depends on runtime conditions, need to decouple `new` from business logic
- **Signal**: `if/switch` choosing which class to instantiate
- **Implementation**: Abstract creator + concrete creators
- **Avoid when**: Only one product type, no variation expected
### Abstract Factory
- **When**: Families of related objects that must be used together (UI themes, DB dialects)
- **Signal**: Multiple factories that produce related objects
- **Avoid when**: Single family — use Factory Method instead
### Builder
- **When**: Object needs 4+ constructor params, optional fields, step-by-step construction
- **Signal**: Telescoping constructors, many optional params, config objects
- **Implementation**: Builder class with fluent API, `.build()` validates
- **Avoid when**: Simple object with 1-3 required params
### Singleton
- **When**: ONLY for true global state — DB connection pool, config, logger
- **Signal**: `getInstance()` pattern
- **DANGER**: Overused. Prefer dependency injection. Singletons hide dependencies and break tests
- **Modern alternative**: DI container (NestJS providers, Spring beans)
### Prototype
- **When**: Cloning complex objects is cheaper than creating from scratch
- **Signal**: Objects with heavy initialization, deep nested state
- **Avoid when**: Objects are simple to construct
## Structural
### Adapter
- **When**: Integrating incompatible interfaces (3rd party lib, legacy API)
- **Signal**: Wrapper that translates interface A to interface B
- **Rule**: Adapter should be thin — only translate, no business logic
### Facade
- **When**: Complex subsystem needs a simple entry point
- **Signal**: Client talks to 5+ classes to do one thing
- **Rule**: Facade doesn't prevent direct access to subsystem
### Decorator
- **When**: Add responsibilities dynamically without subclassing
- **Signal**: Need multiple optional behaviors that compose (logging + caching + auth)
- **Implementation**: Same interface as wrapped object
- **Modern**: Middleware chains (Express/NestJS), Python decorators, TypeScript decorators
### Proxy
- **When**: Control access, lazy loading, caching, logging
- **Signal**: Same interface but with intercepted behavior
- **Modern**: JS Proxy, ORM lazy loading, API rate limiting
### Composite
- **When**: Tree structures — UI components, file systems, org charts
- **Signal**: "Part-whole" hierarchy where leaf and composite treated same
- **Modern**: React component tree, AST nodes
## Behavioral
### Strategy
- **When**: Multiple algorithms interchangeable at runtime
- **Signal**: `if/else` or `switch` on algorithm type
- **Implementation**: Interface + concrete strategies + context
- **Modern**: Function params (pass algorithm as callback)
### Observer / Event Emitter
- **When**: One-to-many dependency, reactive updates
- **Signal**: "When X happens, notify Y, Z, W"
- **Implementation**: EventEmitter, pub/sub, webhooks
- **Modern**: RxJS, EventEmitter, Redis pub/sub, WebSocket broadcasts
### Command
- **When**: Undo/redo, queue operations, macro recording
- **Signal**: Need to parametrize actions, defer execution, support undo
- **Implementation**: Command object with execute() + undo()
### State Machine
- **When**: Object behavior changes based on internal state
- **Signal**: Multiple `if (state === 'X')` checks scattered in code
- **Implementation**: State interface + concrete states + transitions map
- **Modern**: XState, finite state machines, workflow engines
### Repository
- **When**: Abstract data access from business logic
- **Signal**: Business logic directly queries DB
- **Implementation**: Interface with CRUD + query methods, concrete per storage
- **Rule**: Repository returns domain objects, NOT raw DB rows
### Middleware / Chain of Responsibility
- **When**: Sequential processing with optional short-circuit
- **Signal**: Request passes through auth → validation → rate limit → handler
- **Modern**: Express/Koa middleware, NestJS guards/pipes/interceptors
### Dependency Injection
- **When**: ALWAYS for non-trivial apps
- **Signal**: Classes create their own dependencies with `new`
- **Implementation**: Constructor injection (preferred), setter injection
- **Modern**: NestJS modules, Spring, tsyringe, InversifyJS
- **Rule**: Depend on abstractions (interfaces), not concretions
## Architectural Patterns
### MVC / MVVM
- **When**: UI applications with clear data-view separation
- **Modern**: React (View) + Zustand/Redux (Model) + hooks/services (Controller)
### Clean Architecture / Hexagonal
- **When**: Business logic must be independent of framework/DB/UI
- **Layers**: Domain → Use Cases → Interface Adapters → Frameworks
- **Rule**: Dependencies point INWARD only
### CQRS
- **When**: Read and write patterns differ significantly
- **Signal**: Complex queries + simple writes, or read scaling needed
- **Avoid when**: Simple CRUD — overkill
### Event Sourcing
- **When**: Need full audit trail, time-travel debugging, complex domain events
- **Signal**: "What happened" matters more than "current state"
- **DANGER**: Massive complexity increase. Only if truly needed
### Microservices
- **When**: Independent deployment, team autonomy, different scaling needs
- **DANGER**: Overused. Start with monolith, extract when pain points emerge
- **Rule**: If you can't build a well-structured monolith, microservices won't help
## Selection Rules
```
Need to create objects?
├── Many optional params → Builder
├── Runtime type selection → Factory Method
├── Related object families → Abstract Factory
└── Expensive initialization → Prototype
Need to structure code?
├── Incompatible interface → Adapter
├── Simplify complex system → Facade
├── Add optional behavior → Decorator
├── Control access → Proxy
└── Tree structure → Composite
Need to manage behavior?
├── Multiple algorithms → Strategy
├── React to changes → Observer
├── Undo/redo needed → Command
├── State-dependent behavior → State Machine
├── Sequential processing → Middleware
└── Decouple creation from use → DI
```