Go is not an object-oriented programming language but we can still replicate some patterns in it. In this example we are going to see strategy design pattern example. Strategy design pattern behaves like if ... else and switch ... case statements so you give something to it, it knows what exactly to do with it.


Structure


internal/
├── cache
│   ├── cache.go
│   ├── file.go
│   ├── redis.go
│   ├── session.go
│   └── strategy.go
└── main.go

Files


file.go


package cache

import "fmt"

type File struct {}

func (File) push(key, value string, ttl int64) error {
fmt.Println("Pushing [", key, ":", value, "] to file...")

return nil
}

func (File) pop(key string) error {
fmt.Println("Popping [", key, "] from file...")

return nil
}

redis.go


package cache

import "fmt"

type Redis struct {}

func (Redis) push(key, value string, ttl int64) error {
fmt.Println("Pushing [", key, ":", value, "] to redis...")

return nil
}

func (Redis) pop(key string) error {
fmt.Println("Popping [", key, "] from redis...")

return nil
}

session.go


package cache

import "fmt"

type Session struct {}

func (Session) push(key, value string, ttl int64) error {
fmt.Println("Pushing [", key, ":", value, "] to session...")

return nil
}

func (Session) pop(key string) error {
fmt.Println("Popping [", key, "] from session...")

return nil
}

strategy.go


This is the one all the strategies implement.


package cache

type strategy interface {
push(key, value string, ttl int64) error
pop(key string) error
}

cache.go


This is the one we interact with in our code.


package cache

type Cache struct {
Strategy strategy
}

func (c *Cache) Push(key, value string, ttl int64) error {
return c.Strategy.push(key, value, ttl)
}

func (c *Cache) Pop(key string) error {
return c.Strategy.pop(key)
}

main.go


As you can see below, we can use any cache mechanism without changing the code at all. All we have to do is, pick a cache strategy. That's the whole point of the strategy pattern.


package main

import (
"log"

"internal/cache"
)

func main() {
var c = &cache.Cache{}

c.Strategy = cache.File{}
if err := c.Push("key-f", "value-f", 3600); err != nil {
log.Fatalln(err)
}

c.Strategy = cache.Redis{}
if err := c.Pop("key-r"); err != nil {
log.Fatalln(err)
}

c.Strategy = cache.Session{}
if err := c.Push("key-s", "value-s", 3600); err != nil {
log.Fatalln(err)
}
}

Test


Pushing [ key-f : value-f ] to file...
Popping [ key-r ] from redis...
Pushing [ key-s : value-s ] to session...