Go Design Patterns: Comprehensive Concepts, Implementations, and Tests
The article offers a comprehensive Go‑language catalog of classic software design patterns—Interpreter, Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy, Factory Method, Abstract Factory, Builder, Prototype, and Singleton—detailing each pattern’s concept, concrete implementation code, and passing unit‑test results.
This article presents a comprehensive collection of classic software design patterns implemented in Go, covering their concepts, concrete code examples, and test results.
Interpreter Pattern – Defines an expression interface and concrete terminal, or, and and expressions to evaluate feature strings. Example code:
type Expression interface { Interpret(context string) bool }
type terminalExpression struct { matchData string }
func (t *terminalExpression) Interpret(context string) bool { return strings.Contains(context, t.matchData) }
func NewOrExpression(left, right Expression) *orExpression { return &orExpression{left: left, right: right} }
func (o *orExpression) Interpret(context string) bool { return o.left.Interpret(context) || o.right.Interpret(context) }Test output shows correct identification of Antarctica and American characteristics.
Adapter Pattern – Allows incompatible interfaces to work together. The example adapts Huawei and Apple phone charging plugs to a common USB interface.
type HuaweiPlug interface { ConnectTypeC() string }
type ApplePlug interface { ConnectLightning() string }
type HuaweiPhonePlugAdapter struct { huaweiPhone HuaweiPlug }
func (h *HuaweiPhonePlugAdapter) ConnectUSB() string { return fmt.Sprintf("%v adapt to usb ", h.huaweiPhone.ConnectTypeC()) }
type PowerBank struct { brand string }
func (p *PowerBank) Charge(plug CommonPlug) string { return fmt.Sprintf("%v power bank connect usb plug, start charge for %v", p.brand, plug.ConnectUSB()) }Test output demonstrates charging both phone types.
Bridge Pattern – Separates abstraction from implementation. The example models travel experiences with traffic and location interfaces.
type Experience interface { Describe() string }
type travelExperience struct { subject string; traffic Traffic; location Location }
func (t *travelExperience) Describe() string { return fmt.Sprintf("%s is to %s %s and %s", t.subject, t.location.Name(), t.traffic.Transport(), t.location.PlaySports()) }
type airplane struct{}
func (a *airplane) Transport() string { return "by airplane" }Test output shows descriptions for honeymoon travel and desert adventure.
Composite Pattern – Builds tree structures of objects. The example models administrative regions with towns and cities.
type Region interface { Name() string; Population() int; GDP() float64 }
type town struct { name string; population int; gdp float64 }
func (c *town) Name() string { return c.name }
func (c *town) Population() int { return c.population }
func (c *town) GDP() float64 { return c.gdp }
type cities struct { name string; regions map[string]Region }
func (c *cities) Population() int { sum := 0; for _, r := range c.regions { sum += r.Population() }; return sum }Test output aggregates population and GDP for Suzhou.
Decorator Pattern – Adds behavior to objects dynamically. The example decorates a subway station entry with security check and epidemic protection.
type Station interface { Enter() string }
type subwayStation struct { name string }
func (s *subwayStation) Enter() string { return fmt.Sprintf("买票进入%s地铁站。", s.name) }
type securityCheckDecorator struct { station Station }
func (s *securityCheckDecorator) Enter() string { return "行李通过安检;" + s.station.Enter() }
type epidemicProtectionDecorator struct { station Station }
func (e *epidemicProtectionDecorator) Enter() string { return "测量体温,佩戴口罩;" + e.station.Enter() }Test output shows plain entry, entry with security, and entry with both security and epidemic checks.
Facade Pattern – Provides a simple interface to a complex subsystem. The example simulates a Taobao order process.
type TaobaoFacade struct { userService *UserService; productService *ProductService; couponService *CouponService; stockService *StockService; paymentService *PaymentService }
func (t *TaobaoFacade) CreateOrder(userName, productName string, count int) string {
couponInfo := t.couponService.useCoupon()
stockInfo := t.stockService.decreaseFor(productName, count)
sumPrice := t.productService.getProductPrice(productName) * float64(count)
payInfo := t.paymentService.pay(sumPrice)
return fmt.Sprintf("用户%s,购买了%d件%s商品,%s,%s,%s,送货到%s", userName, count, productName, couponInfo, stockInfo, payInfo, t.userService.getUserAddress(userName))
}Test output prints a complete order description.
Flyweight Pattern – Shares common state to reduce memory usage. The example models taxi tracking with shared Taxi objects.
type Taxi struct { licensePlate, color, brand, company string }
func (t *Taxi) LocateFor(monitorMap string, x, y int) string { return fmt.Sprintf("%s,对于车牌号%s,%s,%s品牌,所属%s公司,定位(%d,%d)", monitorMap, t.licensePlate, t.color, t.brand, t.company, x, y) }
type TaxiFactory struct { taxis map[string]*Taxi }
func (f *TaxiFactory) getTaxi(licensePlate, color, brand, company string) *Taxi { if _, ok := f.taxis[licensePlate]; !ok { f.taxis[licensePlate] = &Taxi{licensePlate, color, brand, company} }; return f.taxis[licensePlate] }Test output shows multiple location records for two taxis.
Proxy Pattern – Provides a surrogate for another object. The example implements a house-selling proxy that handles viewing, bargaining, and final contract signing.
type HouseSeller interface { SellHouse(address, buyer string) string }
type houseProxy struct { houseSeller HouseSeller }
func (h *houseProxy) SellHouse(address, buyer string) string {
var buf bytes.Buffer
buf.WriteString(h.viewHouse(address, buyer) + "
")
buf.WriteString(h.preBargain(address, buyer) + "
")
buf.WriteString(h.houseSeller.SellHouse(address, buyer))
return buf.String()
}
func (h *houseProxy) viewHouse(address, buyer string) string { return fmt.Sprintf("带买家%s看位于%s的房屋,并介绍基本情况", buyer, address) }
func (h *houseProxy) preBargain(address, buyer string) string { return "讨价还价后,初步达成购买意向" }Test output shows the three-step selling process.
Factory Method Pattern – Defines an interface for creating an object, but lets subclasses decide which class to instantiate. The example creates corn and millet pancakes.
type Pancake interface { ShowFlour() string; Value() float32 }
type cornPancake struct{}
func (c *cornPancake) ShowFlour() string { return "玉米面" }
func (c *cornPancake) Value() float32 { return 5.0 }
type PancakeCook interface { MakePancake() Pancake }
type cornPancakeCook struct{}
func (c *cornPancakeCook) MakePancake() Pancake { return &cornPancake{} }
type PancakeVendor struct { PancakeCook }
func (v *PancakeVendor) SellPancake() float32 { return v.MakePancake().Value() }Test output prints values for corn and millet pancakes.
Abstract Factory Pattern – Provides an interface for creating families of related objects. The example models breakfast, lunch, and dinner cooks producing food and drink.
type Cook interface { MakeFood() Food; MakeDrink() Drink }
type Food interface { Eaten() string }
type Drink interface { Drunk() string }
type breakfastCook struct{}
func (b *breakfastCook) MakeFood() Food { return &cakeFood{"切片面包"} }
func (b *breakfastCook) MakeDrink() Drink { return &gruelDrink{"小米粥"} }
func HaveMeal(c Cook) string { return fmt.Sprintf("%s %s", c.MakeFood().Eaten(), c.MakeDrink().Drunk()) }
// Test prints breakfast, lunch, and dinner meals.Test output shows combined food and drink descriptions.
Builder (Generator) Pattern – Constructs complex objects step by step. The example builds pancakes with configurable paste quantity, eggs, wafer, and flavors.
type PancakeBuilder interface { PutPaste(q Quantity); PutEgg(num int); PutWafer(); PutFlavour(coriander, shallot, sauce bool); Build() *Pancake }
type normalPancakeBuilder struct { pasteQuantity Quantity; eggNum int; friedWafer string; hasCoriander, hasShallot, hasHotSauce bool }
func (b *normalPancakeBuilder) Build() *Pancake { return &Pancake{pasteQuantity: b.pasteQuantity, eggNum: b.eggNum, wafer: b.friedWafer, hasCoriander: b.hasCoriander, hasShallot: b.hasShallot, hasSauce: b.hasHotSauce} }
type PancakeCook struct { builder PancakeBuilder }
func (p *PancakeCook) MakePancake() *Pancake { p.builder.PutPaste(Middle); p.builder.PutEgg(1); p.builder.PutWafer(); p.builder.PutFlavour(true, true, true); return p.builder.Build() }
func (p *PancakeCook) MakeBigPancake() *Pancake { p.builder.PutPaste(Large); p.builder.PutEgg(3); p.builder.PutWafer(); p.builder.PutFlavour(true, true, true); return p.builder.Build() }Test output displays the created pancake structs.
Prototype Pattern – Creates new objects by copying an existing object. The example clones a newspaper and a resume using a copier.
type Paper interface { io.Reader; Clone() Paper }
type Newspaper struct { headline, content string }
func (n *Newspaper) Clone() Paper { return &Newspaper{headline: n.headline + "_copied", content: n.content} }
type Resume struct { name string; age int; experience string }
func (r *Resume) Clone() Paper { return &Resume{name: r.name + "_copied", age: r.age, experience: r.experience} }
type Copier struct { name string }
func (c *Copier) copy(p Paper) Paper { fmt.Printf("copier name:%v is copying:%v ", c.name, reflect.TypeOf(p).String()); return p.Clone() }
// Test prints cloned content.Test output shows cloned newspaper and resume with modified identifiers.
Singleton Pattern – Ensures a class has only one instance. The example provides a single Earth instance using sync.Once.
type earth struct { desc string }
var theEarth *earth
var once sync.Once
func TheEarth() *earth { once.Do(func(){ theEarth = &earth{desc: "美丽的地球,孕育了生命。"} }); return theEarth }
// Test prints the Earth description.All patterns include unit tests that pass, demonstrating correct behavior.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent Cloud Developer
Official Tencent Cloud community account that brings together developers, shares practical tech insights, and fosters an influential tech exchange community.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
