Rethinking GRASP (General Responsibility Assignment Software Patterns), SOLID (Single responsibility, Openβclosed, Liskov substitution, Interface segregation, Dependency inversion), GoF (Gang of Four) patterns, for Frontend (browsers) & Backend (node.js, other runtimes) development with JavaScript and TypeScript
- 𧩠Patterns
- π’ GoF patterns for Node.js and JavaScript (seminar fragment)
- π Creational patterns
- Abstract factory β creates related objects belonging to one family without specifying their concrete classes, e.g., UI components for different platforms.
- Builder β step-by-step assembly of a complex configurable object, often using chaining, e.g., Query Builder or Form Generator.
- Factory β function or method that creates objects using different techniques: assembling from literals and methods, mixins, setPrototypeOf.
- Factory Method β chooses the correct abstraction to create an instance; in JavaScript, this can be implemented using
if
,switch
, or selection from a collection (dictionary). - Prototype β creates objects by cloning a prepared instance to save resources (not to be confused with Prototype-programming, which is closer to Flyweight).
- Flyweight β saves memory allocation by sharing common state among multiple instances.
- Singleton β provides global access to a single instance; often considered an anti-pattern, easiest implemented via ESM/CJS module caching exported refs.
- Object Pool β reuses pre-created objects to save resources during frequent creation and destruction.
- π€ Structural patterns
- Adapter β converts an incompatible interface into a compatible one, enabling third-party component usage without altering its code; can even transform a function contract into an object or vice versa.
- Wrapper β function wrapper that delegates calls and adds behavior; a specialized case of Adapter.
- Boxing β wraps primitives into object types to add methods or unify interfaces, e.g., narrowing
String
toAddressString
. - Decorator
- Decorator β dynamically extends behavior without inheritance, typically via composition and declarative syntax, effectively adding metadata.
- Proxy β controls access to an object by intercepting calls, reads, and writes; useful for lazy initialization, caching, and security; can be implemented via GoF or native JavaScript Proxy.
- Bridge β separates two or more abstraction hierarchies via composition or aggregation, allowing them to evolve independently.
- Composite β implements a common interface to uniformly handle individual objects and their tree structures, e.g., DOM or file systems.
- Facade β simplifies access to a complex system, providing a unified and clear interface, hiding and protecting internal complexity.
- Flyweight β saves memory allocation by sharing common state among multiple instances.
- β‘ Behavioral patterns
- Chain of Responsibility β passes control through a chain of handlers, selecting a responsible one; all handlers can read, but only one will modify.
- Middleware β handler chain similar to CoR, but each can modify state and pass control to the next one, potentially leading to race conditions and conflicts.
- Command β encapsulates an action (execution request) and parameters into an object, allowing queuing, cancellation, repetition, etc.
- Interpreter β implements a DSL language (Domain Specific Language) or parses expressions into AST (Abstract Syntax Tree) for interpretation.
- Iterator β sequentially traverses collections or streams element-by-element without exposing all data; JavaScript provides built-in Iterator and AsyncIterator.
- Mediator β optimizes communication between N components, centralizing interaction to reduce coupling from
N*(N-1)/2
down toN
. - Memento β saves and restores snapshots of an object's state without direct access to its internal state.
- Observable β notifies subscribers about changes to an object's state via Events:
- EventEmitter for Node.js: Observable + listener
- EventTarget for Web API: EventTarget + Event (CustomEvent) + listener
- Signals
- State β implements a Finite State Machine (FSM) where methods represent transitions, and state is composed into abstraction and switched during transitions.
- Strategy β selects interchangeable behavior at runtime from a collection of implementations: functions, objects, or classes
- Template method β defines algorithm steps, allowing subclasses to override individual steps while defaulting to the superclass behavior.
- Visitor β adds operations to objects without altering their classes, separating structure and behavior into distinct abstractions.
- Revealing Constructor β changes behavior without inheritance, injecting functionality into constructors via functions or objects describing the behavior.
- 𧩠GRASP patterns
- π’ Intro video
- GRASP Overview
- Part 1 - GRASP for Node.js and Javascript
- Part 2 - coming soon
- Information expert
- Creator
- Controller
- Indirection
- Low coupling
- High cohesion
- Polymorphism
- Protected variations
- Pure fabrication
- Real code examples
- π’ Intro video
- 𧩠SOLID Patterns