CODESAMPLE

Bridge - Go

Share on:

The Bridge pattern is a structural design pattern that lets you split an abstraction from its implementation so that objects can have different implementations. This is useful when you want to avoid a tight coupling between abstract and concrete implementations, or when you have multiple independent abstractions that might require different implementations.

The Go implementation defines an Abstraction interface with a method that takes an Implementor interface as a dependency. Different Abstractions can use the same Implementor, and the same Abstraction can switch between different Implementors at runtime. This example presents a Shape abstraction and Color implementation, allowing for combinations like a “Red Circle” or “Blue Square” without creating rigid class hierarchies. Go’s interfaces and composition naturally lend themselves to this pattern, maximizing flexibility without inheritance.

package main

import "fmt"

// Implementor interface
type Implementor interface {
	Operation() string
}

// Concrete Implementors
type ConcreteImplementorA struct{}

func (c *ConcreteImplementorA) Operation() string {
	return "ConcreteImplementorA's operation"
}

type ConcreteImplementorB struct{}

func (c *ConcreteImplementorB) Operation() string {
	return "ConcreteImplementorB's operation"
}

// Abstraction interface
type Abstraction interface {
	SetImplementor(impl Implementor)
	Operation() string
}

// Concrete Abstractions
type ConcreteAbstraction struct {
	implementor Implementor
}

func (c *ConcreteAbstraction) SetImplementor(impl Implementor) {
	c.implementor = impl
}

func (c *ConcreteAbstraction) Operation() string {
	return c.implementor.Operation()
}

// Example Usage - Shape and Color analogy
type Shape interface {
	Draw() string
}

type Circle struct {
	color Implementor
}

func (c *Circle) SetColor(color Implementor) {
	c.color = color
}

func (c *Circle) Draw() string {
	return fmt.Sprintf("Drawing a circle with %s", c.color.Operation())
}


func main() {
	implementorA := &ConcreteImplementorA{}
	implementorB := &ConcreteImplementorB{}

	abstraction := &ConcreteAbstraction{}
	abstraction.SetImplementor(implementorA)
	fmt.Println(abstraction.Operation()) // Output: ConcreteImplementorA's operation

	abstraction.SetImplementor(implementorB)
	fmt.Println(abstraction.Operation()) // Output: ConcreteImplementorB's operation

	redColor := &ConcreteImplementorA{}
	blueColor := &ConcreteImplementorB{}

	circle := &Circle{}
	circle.SetColor(redColor)
	fmt.Println(circle.Draw()) // Output: Drawing a circle with ConcreteImplementorA's operation

	circle.SetColor(blueColor)
	fmt.Println(circle.Draw()) // Output: Drawing a circle with ConcreteImplementorB's operation
}