ποΈ GoF Patterns: Java vs Go, in the wild, in Orbit
Language lens
Java expresses patterns with classes + interfaces + inheritance + frameworks. Go expresses the same ideas with small interfaces, first-class functions, embedding, and closures. Many GoF patterns collapse into βpass a functionβ in Go.
Creational
| Pattern | Intent | Java / in the wild | Go idiom | Orbit usage |
|---|---|---|---|---|
| Factory Method | Defer instantiation to a creator | BeanFactory, Calendar.getInstance() | NewX(...) constructors returning interfaces | StepExecutorFactory.forType("llm") |
| Abstract Factory | Families of related objects | JDBC Connection β Statement | Interface returning a family of interfaces | Provider SDK family: client + tokenizer + embedder |
| Builder | Step-by-step complex construction | RestClient.builder(), Lombok @Builder, records + builders | β Functional options: NewServer(addr, WithTimeout(5*time.Second)) | WorkflowDefinition.builder(), gateway client options |
| Singleton | One instance | Spring singleton scope, enum singleton | sync.Once, a package-level var | Config, provider registry (prefer DI over global singletons) |
| Prototype | Clone existing objects | clone(), prototype scope | Struct copy (watch slice/map aliasing!) | Clone a workflow version to create a draft |
Structural
| Pattern | Intent | Java / in the wild | Go idiom | Orbit usage |
|---|---|---|---|---|
| Adapter | Convert one interface to another | HandlerAdapter, Arrays.asList | http.HandlerFunc adapts a func to http.Handler β | Anthropic/OpenAI/Ollama responses β a common ChatResponse |
| Decorator | Add behavior by wrapping | java.io streams, Collections.synchronizedList | β Middleware: func(http.Handler) http.Handler | Gateway: logging β auth β quota β cache β provider |
| Proxy | Control access to an object | Spring AOP, JPA lazy proxies | httputil.ReverseProxy, gRPC interceptors | Tool proxy that enforces scopes + approvals |
| Facade | A simple API over a complex subsystem | JdbcTemplate, RestTemplate | Package-level API over internal packages | OrbitClient SDK |
| Composite | Tree of uniform objects | UI trees, CompositeCacheManager | io.MultiWriter, an interface on tree nodes | Workflow DAG: parallel/map steps containing steps |
| Bridge | Separate abstraction from implementation | JDBC API β drivers, SLF4J β Logback | slog.Logger β slog.Handler β | Vector store abstraction β pgvector/Qdrant |
| Flyweight | Share fine-grained immutable state | Integer.valueOf cache, String pool | Interned strings, shared read-only structs | Shared tokenizer vocab, prompt templates |
Behavioral
| Pattern | Intent | Java / in the wild | Go idiom | Orbit usage |
|---|---|---|---|---|
| Strategy β | Swap algorithms | Comparator, PlatformTransactionManager | An interface or a func type | Retry policies, routing policies, chunking strategies |
| Chain of Responsibility | Pass along handlers | Servlet filters, Security FilterChain | Middleware chains, gRPC interceptors | Guardrail chain: PII β injection check β schema |
| Command | Request as an object (queue, retry, undo) | Runnable, Callable | Structs with Execute(ctx), closures | Each step execution is a command in the task queue |
| State β | Behavior depends on state | Order lifecycles, Spring Statemachine | A state enum + transition table, or state funcs (Rob Pikeβs lexer) | Run/step lifecycle: PENDING β RUNNING β WAITING β COMPLETED/FAILED/COMPENSATING |
| Observer | Notify subscribers | ApplicationEventPublisher, listeners | Channels, callbacks | Run events β stream service, webhooks |
| Template Method | Skeleton with overridable steps | JdbcTemplate, AbstractController | Rare β compose with function params | Base step executor: validate β execute β record |
| Iterator | Sequential access | Iterator, Streams | iter.Seq, range-over-func | Paginated run history cursor |
| Mediator | Centralize communication | Message brokers, ApplicationEventMulticaster | A central goroutine owning state | Supervisor agent coordinating sub-agents |
| Memento | Capture and restore state | Undo stacks | Snapshots | Run checkpoints, LangGraph checkpoints |
| Interpreter | Evaluate a language | SpEL, regex | β Pratt parser (Writing an Interpreter in Go) | orbit-expr conditions |
| Visitor | Operations over a structure | FileVisitor, compiler ASTs | Type switch over a sealed-ish interface | Validate/optimize/render a workflow DAG; modern Java: sealed interfaces + pattern-matching switch |
SOLID (quick reference)
Single responsibility Β· Open/closed (extend via Strategy/Decorator) Β· Liskov substitution Β· Interface segregation (Goβs small interfaces!) Β· Dependency inversion (depend on ports; adapters at the edges)
π¬ Katas
- Implement the LLM provider layer: Strategy + Adapter + Decorator (retry, logging, cache) in both languages
- The step lifecycle as a State pattern with an explicit transition table + property tests (no illegal transitions)
- Visitor in classic Java vs sealed interfaces +
switchpattern matching β compare the readability - Go functional options vs a Java builder for the same
GatewayClientconfig - Refactor a 200-line
if/elsestep runner into Command + Factory + Strategy