Design Patterns in Go with Examples: From A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Design Patterns in Go with Examples: From A to Z



Design Patterns are time-tested architectural solutions that help Go developers create flexible, scalable, and maintainable code. Unlike classical OOP languages, Go offers its own unique approach to implementing patterns through interfaces, composition, and goroutines. In this article, we will break down the main design patterns in Go with specific code examples.



1. Creational Patterns



Creational patterns are responsible for object creation, making the system independent of how objects are created.



1.1. Singleton



The Singleton guarantees that a class has only one instance. In Go, this is often implemented using sync.Once for thread safety.



package main

import ( "fmt" "sync")

type Database struct { connection string}

var ( instance *Database once sync.Once)

func GetDatabaseInstance() *Database { once.Do(func() { instance = &Database{connection: "postgres://localhost:5432/mydb"} fmt.Println("Created a single database connection") }) return instance}

func main() { db1 := GetDatabaseInstance() db2 := GetDatabaseInstance() fmt.Println(db1 == db2) // true}


1.2. Factory Method



The Factory delegates object creation to subclasses. In Go, this is done using interfaces.



package main

import "fmt"

// Product interfacetype Transport interface { Deliver() string}

// Concrete productstype Truck struct{}func (t Truck) Deliver() string { return "Delivery by land" }

type Ship struct{}func (s Ship) Deliver() string { return "Delivery by sea" }

// Factorytype LogisticsFactory interface { CreateTransport() Transport}

type RoadLogistics struct{}func (r RoadLogistics) CreateTransport() Transport { return Truck{} }

type SeaLogistics struct{}func (s SeaLogistics) CreateTransport() Transport { return Ship{} }

func main() { var factory LogisticsFactory = RoadLogistics{} transport := factory.CreateTransport() fmt.Println(transport.Deliver()) // Delivery by land}


2. Structural Patterns



Structural patterns help organize classes and objects into larger structures.



2.1. Adapter



The Adapter allows objects with incompatible interfaces to work together. In Go, this is solved through a wrapper.



package main

import "fmt"

// Old interfacetype OldPrinter interface { PrintOld(data string)}

type LegacyPrinter struct{}func (l LegacyPrinter) PrintOld(data string) { fmt.Println("Legacy:", data)}

// New interfacetype NewPrinter interface { PrintNew(data string)}

// Adaptertype PrinterAdapter struct { OldPrinter OldPrinter}

func (a PrinterAdapter) PrintNew(data string) { a.OldPrinter.PrintOld(data)}

func main() { legacy := LegacyPrinter{} adapter := PrinterAdapter{OldPrinter: legacy} adapter.PrintNew("Hello, Go!") // Legacy: Hello, Go!}


2.2. Composite



The Composite allows treating groups of objects as a single object. It is ideal for tree structures.



package main

import "fmt"

// Component interfacetype Graphic interface { Draw() string}

// Leaf elementtype Circle struct{}func (c Circle) Draw() string { return "Drawing a circle" }

// Containertype CompoundGraphic struct { children []Graphic}

func (cg *CompoundGraphic) Add(g Graphic) { cg.children = append(cg.children, g)}

func (cg *CompoundGraphic) Draw() string { result := "Compound figure:" for _, child := range cg.children { result += " - " + c

Blogs

Book Recommendations