πŸ›οΈ 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

PatternIntentJava / in the wildGo idiomOrbit usage
Factory MethodDefer instantiation to a creatorBeanFactory, Calendar.getInstance()NewX(...) constructors returning interfacesStepExecutorFactory.forType("llm")
Abstract FactoryFamilies of related objectsJDBC Connection β†’ StatementInterface returning a family of interfacesProvider SDK family: client + tokenizer + embedder
BuilderStep-by-step complex constructionRestClient.builder(), Lombok @Builder, records + builders⭐ Functional options: NewServer(addr, WithTimeout(5*time.Second))WorkflowDefinition.builder(), gateway client options
SingletonOne instanceSpring singleton scope, enum singletonsync.Once, a package-level varConfig, provider registry (prefer DI over global singletons)
PrototypeClone existing objectsclone(), prototype scopeStruct copy (watch slice/map aliasing!)Clone a workflow version to create a draft

Structural

PatternIntentJava / in the wildGo idiomOrbit usage
AdapterConvert one interface to anotherHandlerAdapter, Arrays.asListhttp.HandlerFunc adapts a func to http.Handler ⭐Anthropic/OpenAI/Ollama responses β†’ a common ChatResponse
DecoratorAdd behavior by wrappingjava.io streams, Collections.synchronizedList⭐ Middleware: func(http.Handler) http.HandlerGateway: logging β†’ auth β†’ quota β†’ cache β†’ provider
ProxyControl access to an objectSpring AOP, JPA lazy proxieshttputil.ReverseProxy, gRPC interceptorsTool proxy that enforces scopes + approvals
FacadeA simple API over a complex subsystemJdbcTemplate, RestTemplatePackage-level API over internal packagesOrbitClient SDK
CompositeTree of uniform objectsUI trees, CompositeCacheManagerio.MultiWriter, an interface on tree nodesWorkflow DAG: parallel/map steps containing steps
BridgeSeparate abstraction from implementationJDBC API ↔ drivers, SLF4J ↔ Logbackslog.Logger ↔ slog.Handler ⭐Vector store abstraction ↔ pgvector/Qdrant
FlyweightShare fine-grained immutable stateInteger.valueOf cache, String poolInterned strings, shared read-only structsShared tokenizer vocab, prompt templates

Behavioral

PatternIntentJava / in the wildGo idiomOrbit usage
Strategy ⭐Swap algorithmsComparator, PlatformTransactionManagerAn interface or a func typeRetry policies, routing policies, chunking strategies
Chain of ResponsibilityPass along handlersServlet filters, Security FilterChainMiddleware chains, gRPC interceptorsGuardrail chain: PII β†’ injection check β†’ schema
CommandRequest as an object (queue, retry, undo)Runnable, CallableStructs with Execute(ctx), closuresEach step execution is a command in the task queue
State ⭐Behavior depends on stateOrder lifecycles, Spring StatemachineA state enum + transition table, or state funcs (Rob Pike’s lexer)Run/step lifecycle: PENDING β†’ RUNNING β†’ WAITING β†’ COMPLETED/FAILED/COMPENSATING
ObserverNotify subscribersApplicationEventPublisher, listenersChannels, callbacksRun events β†’ stream service, webhooks
Template MethodSkeleton with overridable stepsJdbcTemplate, AbstractControllerRare β†’ compose with function paramsBase step executor: validate β†’ execute β†’ record
IteratorSequential accessIterator, Streamsiter.Seq, range-over-funcPaginated run history cursor
MediatorCentralize communicationMessage brokers, ApplicationEventMulticasterA central goroutine owning stateSupervisor agent coordinating sub-agents
MementoCapture and restore stateUndo stacksSnapshotsRun checkpoints, LangGraph checkpoints
InterpreterEvaluate a languageSpEL, regex⭐ Pratt parser (Writing an Interpreter in Go)orbit-expr conditions
VisitorOperations over a structureFileVisitor, compiler ASTsType switch over a sealed-ish interfaceValidate/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 + switch pattern matching β†’ compare the readability
  • Go functional options vs a Java builder for the same GatewayClient config
  • Refactor a 200-line if/else step runner into Command + Factory + Strategy