Hey there!
Another week, another design pattern. This week I'm bringing you the Bridge Desing Pattern.
Let's assume you are working with shapes. Thus far you've implemented a Square and a Circle with a getArea() and a getPerimeter() functions.
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 Colour to your shapes and you want to print the colour for each shape. You would find yourself with a complicated and exponentially growing tree of coloured shapes like this:
If you keep adding shapes and colours, you'd get a lot of different objects which would actually behave similarly and would be tedious, awful and inefficient to escalate.
So we are going to use the bridge pattern for this issue.
Let's define a new Colour interface which will enforce a printColour() method on the implementing structs:
type Colour interface {
printColour()
}
Then we can create new colour structures which will implement the printColour() method on their 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 colour attribute to our shapes and add the colour methods that we want to impose on our shape interface:
type Shape interface {
getArea() float32
getPerimeter() float32
getColour()
setColour(colour Colour)
}
Again, let's go back to our shapes 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:
Since everything was set up, let's test it on our main method:
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 the result will look like this:
go run .
Square's area is: 17.639997
Square's perimeter is: 16.8
Square says: I'm Red!
Square says: I'm Blue!
Circle's area is: 149.57124
Circle's perimeter is: 43.35398
Circle says: I'm Blue!
Circle says: I'm Red!
And that's it for today! I hope you liked it and it proves useful for your projects.
Happy coding!
Top comments (2)
Hi, nice to know the name of a very common design pattern which I often use. In case you'd like to get rid of the grid lines from your draw.io drawings (I guessed you used that) you may also export it as image. As I did in my recent post: dev.to/davidkroell/go-concurrency-...
Thanks! I didn't know how to do it. I'll start exporting the images from now on