Installs into .claude/skills of the current project.
Are you the author of Functional Translating Gof Patterns?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/yutna-functional-translating-gof-patterns)
---
name: functional-translating-gof-patterns
description: Use when reaching for a factory, strategy, visitor or other class-based pattern, when porting object-oriented code, or when a pattern feels heavy.
license: MIT
metadata:
pack: functional-design-skills
version: 3.3.0
---
# Translating GoF Patterns
**In this pack:** [how much design a task warrants](../functional-design/references/calibration.md),
[the notation](../functional-design/references/notation.md), and
[syntax per language](../functional-design/SKILL.md#language-packs).
## Overview
The classic design patterns are not obsolete in functional code; most of
them are simply smaller. A pattern that needed an interface, two classes,
and a registry usually becomes a function, a function type, or a choice
type. The problem each pattern solves is still real; the scaffolding
built to solve it in a language without first-class functions is not.
Knowing the translation matters for two reasons: it stops a familiar name
dragging a heavy implementation into a functional codebase, and it makes
object-oriented code readable when porting it.
## When to use
- About to name something `...Factory`, `...Strategy`, or `...Manager`
- Porting object-oriented code to a functional style
- A pattern's usual implementation feels like ceremony here
- Choosing how to make one piece of behaviour vary
Not for: deciding module boundaries, which is
[functional-designing-deep-modules](../functional-designing-deep-modules/SKILL.md).
## The translation table
| Pattern | Functional form |
| ---------------- | ----------------------------------------- |
| Strategy | A function parameter |
| Command | A value describing the action |
| Factory | A function returning a value |
| Abstract Factory | A record of constructor functions |
| Template Method | A function taking the varying steps |
| Decorator | A function wrapping a function |
| Adapter | A conversion function |
| Facade | A module with a small interface |
| Observer | Return events; the shell delivers them |
| Iterator | A lazy sequence |
| State | A choice type plus transition functions |
| Composite | A recursive choice type plus a fold |
| Visitor | A fold, or exhaustive matching |
| Singleton | A value, passed in |
| Builder | A record with defaults, or a constructor |
| Chain of resp. | A list of functions returning `Option` |
| Memento | The previous immutable value |
| Flyweight | One immutable value, created once, shared |
| Interpreter | A choice type plus an evaluation function |
| Mediator | A workflow function |
Each is worked out in [catalog.md](references/catalog.md).
## The three that change most
**Strategy becomes a parameter.** No interface, no implementations, no
registry.
```text
-- before: an interface and three classes
-- after:
roundTotal : RoundingRule -> PricedBooking -> PricedBooking
```
**Visitor becomes a fold or a match.** The double-dispatch machinery
exists to work around a language that cannot match on a value's case.
Where matching is available, use it.
```text
type Shape = Circle of Radius | Rect of (W, H) | Triangle of (B, H)
area : Shape -> Area
area s =
match s with
| Circle r -> pi * r * r
| Rect (w, h) -> w * h
| Triangle (b, h) -> b * h / 2
```
**Observer becomes returned events.** Instead of registering callbacks
that fire inside the decision, return what happened and let the shell
deliver it. The decision stays pure and testable, and the set of
listeners becomes visible in one place.
```text
confirmBooking :
Catalogue -> Instant -> UnvalidatedBooking
-> Result<List<ConfirmBookingEvent>, ConfirmBookingError>
```
## Patterns that stay useful
Not everything shrinks to nothing:
- **Command** is a value describing the action, which is what queues,
audit trails, and replay are built on.
- **Interpreter** is a genuine functional pattern: a choice type for the
language, a pure evaluator, and the option of several evaluators.
- **Decorator** remains useful for cross-cutting guarantees such as
retry, but see the caution in
[functional-separating-layers](../functional-separating-layers/SKILL.md).
- **Adapter** is unavoidable at every boundary, and should be an
explicit named function. See
[functional-crossing-io-boundaries](../functional-crossing-io-boundaries/SKILL.md).
- **Composite** is exactly a recursive choice type, and folds over it are
the natural way to consume one.
## The caution
A pattern applied because it is known, rather than because the problem
called for it, adds interface without adding capability. The failure mode
is the same as over-abstraction generally: a factory that produces one
type, a strategy with one implementation, a mediator that forwards.
Before naming anything after a pattern, ask:
1. What varies here, and does it vary in reality or only in principle?
2. What is the simplest thing that lets it vary? Usually a parameter.
3. Would a reader who does not know the pattern understand this code?
## Red flags
- A type name ending in `Factory`, `Strategy`, `Manager`, `Helper`
- An interface with one implementation and no test benefit
- A registry mapping names to constructors, used from one place
- Callbacks fired from inside a domain function
- Double dispatch where a match would do
- A builder for a record with three fields
## Common mistakes
- **Porting the structure instead of the intent.** The classes are the
workaround; the intent is what to keep.
- **Reaching for a plugin mechanism when the cases are fixed.** Use a
choice type and exhaustive matching. See
[functional-applying-solid-functionally](../functional-applying-solid-functionally/SKILL.md).
- **Keeping the pattern's vocabulary.** Name things for the domain, not
for the pattern.
- **Wrapping functions in objects to "keep it consistent".** Consistency
with the framework is not worth the interface.
## Related skills
- [functional-applying-solid-functionally](../functional-applying-solid-functionally/SKILL.md)
- [functional-folding-over-data](../functional-folding-over-data/SKILL.md)
- [functional-modeling-state-machines](../functional-modeling-state-machines/SKILL.md)
- [functional-composing-functions](../functional-composing-functions/SKILL.md)
## Further reading
- [catalog.md](references/catalog.md) works each pattern through, with
what it solves, the functional form, and when the pattern is still
worth naming.