Skip to content
Back to skills

Functional Translating Gof Patterns

ASecurity

Use when reaching for a factory, strategy, visitor or other class-based pattern, when porting object-oriented code, or when a pattern feels heavy.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 21, 2026
ai-agentsgoshellrails

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 21, 2026

npx -y skills add yutna/functional-design-skills --skill functional-translating-gof-patterns --agent claude-code

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.

Security grade badge for Functional Translating Gof Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/yutna-functional-translating-gof-patterns/badge)](https://www.skillsdirectory.com/skills/yutna-functional-translating-gof-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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.

Files in this skill

  • SKILL.md6.6 KB
  • references/catalog.md7.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.