What is the Bridge Design Pattern in Go?

Let’s assume you are working with shapes and that, thus far, you’ve implemented a Square and a Circle with a getArea() and a getPerimeter() function:

type Shape interface {
    getArea() float32
    getPerimeter() float32
}
type Square struct {
    side   float32
}

func (s *Square) getArea() float32 {
    return s.side * s.side
}

func (s *Square) getPerimeter() float32 {
    return s.side * 4
}

func NewSquare(side float32) *Square {
    s := &Square{side: side}
    return s
}
type Circle struct {
    radius float32
}

func (c *Circle) getArea() float32 {
    return math.Pi * c.radius * c.radius
}

func (c *Circle) getPerimeter() float32 {
    return 2 * math.Pi * c.radius
}

func NewCircle(radius float32) *Circle {
    c := &Circle{radius: radius}
    return c
}

However, you want to add color to your shapes and print the color for each shape. You would then find yourself with a complicated, exponentially growing tree of colored shapes like this:

If you keep adding shapes and colors, you would get a lot of different objects that behave similarly and are tedious, awful, and inefficient to escalate.

So, we are going to use the bridge pattern for this issue.

Let’s define a new color interface that will enforce a printColour() method on the implementing structs:

type Colour interface {
    printColour()
}

We can then create a new color structure that will implement the printColour() method in its own way:

type RedColour struct{}

func (r *RedColour) printColour() {
    fmt.Println("I'm Red!")
}
type BlueColour struct {
}

func (b *BlueColour) printColour() {
    fmt.Println("I'm Blue!")
}

So, now, we can actually add the color attribute to our shapes and the color methods we want to impose on our shape interface:

type Shape interface {
    getArea() float32
    getPerimeter() float32
    getColour()
    setColour(colour Colour)
}

Let’s go back to our shape’s structs and implement the methods:

func (s *Square) setColour(colour Colour) {
    s.colour = colour
}

func (s *Square) getColour() {
    fmt.Print("Square says: ")
    s.colour.printColour()
}
func (c *Circle) setColour(colour Colour) {
    c.colour = colour
}

func (c *Circle) getColour() {
    fmt.Print("Circle says: ")
    c.colour.printColour()
}

Right now, our program will look something like this:

Code

package main
import "fmt"
import "math"
/*
Bridge:
A mechanism that decouples an interface (hierarchy)
from an implementation (hierarchy)
*/
type Shape interface {
getArea() float32
getPerimeter() float32
getColour()
setColour(colour Colour)
}
type Square struct {
side float32
colour Colour
}
func (s *Square) getArea() float32 {
return s.side * s.side
}
func (s *Square) getPerimeter() float32 {
return s.side * 4
}
func (s *Square) setColour(colour Colour) {
s.colour = colour
}
func (s *Square) getColour() {
fmt.Print("Square says: ")
s.colour.printColour()
}
func NewSquare(side float32, colour Colour) *Square {
s := &Square{side: side}
s.setColour(colour)
return s
}
type Circle struct {
radius float32
colour Colour
}
func (c *Circle) getArea() float32 {
return math.Pi * c.radius * c.radius
}
func (c *Circle) getPerimeter() float32 {
return 2 * math.Pi * c.radius
}
func (c *Circle) setColour(colour Colour) {
c.colour = colour
}
func (c *Circle) getColour() {
fmt.Print("Circle says: ")
c.colour.printColour()
}
func NewCircle(radius float32, colour Colour) *Circle {
c := &Circle{radius: radius}
c.setColour(colour)
return c
}
type Colour interface {
printColour()
}
type RedColour struct{}
func (r *RedColour) printColour() {
fmt.Println("I'm Red!")
}
type BlueColour struct {
}
func (b *BlueColour) printColour() {
fmt.Println("I'm Blue!")
}
func main() {
r := &RedColour{}
b := &BlueColour{}
s := NewSquare(4.2, r)
c := NewCircle(6.9, b)
fmt.Println("Square's area is:", s.getArea())
fmt.Println("Square's perimeter is:", s.getPerimeter())
s.getColour()
s.setColour(b)
s.getColour()
fmt.Println()
fmt.Println("Circle's area is:", c.getArea())
fmt.Println("Circle's perimeter is:", c.getPerimeter())
c.getColour()
c.setColour(r)
c.getColour()
}

And that’s it for today! I hope you liked it and that it proves useful for your projects.

Check out the four other design patterns in GO:

Happy coding!

Free Resources

Attributions:
  1. undefined by undefined
Copyright ©2025 Educative, Inc. All rights reserved