Friend spotlight!
Whimsical Animations course
Friend spotlight!
NEW Whimsical Animations course
Friend spotlight! NEW Whimsical Animations course
huge discount only this week
Friend spotlight! Want to make your project stand out? NEW Whimsical Animations course huge discount only this week
Strategy

Strategy em Go

O Strategy é um padrão de projeto comportamental que transforma um conjunto de comportamentos em objetos e os torna intercambiáveis dentro do objeto de contexto original.

O objeto original, chamado contexto, mantém uma referência a um objeto strategy e o delega a execução do comportamento. Para alterar a maneira como o contexto executa seu trabalho, outros objetos podem substituir o objeto strategy atualmente vinculado por outro.

Exemplo conceitual

Suponha que você esteja criando um cache na memória. Por estar na memória, seu tamanho é limitado. Sempre que atinge seu tamanho máximo, algumas entradas precisam ser despejadas para liberar espaço. Isso pode acontecer por meio de vários algoritmos. Alguns dos algoritmos populares são:

  • Least Recently Used (LRU - Menos Usada Recentemente): remove uma entrada que foi menos usada recentemente.
  • First In, First Out (FIFO - Primeira a entrar, primeira a sair): remove uma entrada que foi criada primeiro.
  • Least Frequently Used (LFU - Menos Usada Frequentemente): remove uma entrada que foi usada com menos frequência.

O problema é como desacoplar nossa classe de cache desses algoritmos para que possamos alterar o algoritmo em tempo de execução. Além disso, a classe de cache não deve ser alterada quando um novo algoritmo está sendo adicionado.

É aqui que o padrão Strategy entra em cena. Ele sugere a criação de uma família do algoritmo com cada algoritmo tendo sua própria classe. Cada uma dessas classes segue a mesma interface, e isso torna o algoritmo intercambiável dentro da família. Digamos que o nome comum da interface seja evictionAlgo.

Agora nossa classe de cache principal irá incorporar a interface evictionAlgo. Em vez de implementar todos os tipos de algoritmos de remoção em si, nossa classe de cache irá delegar tudo para a interface evictionAlgo. Como evictionAlgo é uma interface, podemos executar a alteração do algoritmo em tempo de execução para LRU, FIFO, LFU sem qualquer alteração na classe de cache.

evictionAlgo.go: Interface de estratégia

package main

type EvictionAlgo interface {
	evict(c *Cache)
}

fifo.go: Estratégia concreta

package main

import "fmt"

type Fifo struct {
}

func (l *Fifo) evict(c *Cache) {
	fmt.Println("Evicting by fifo strtegy")
}

lru.go: Estratégia concreta

package main

import "fmt"

type Lru struct {
}

func (l *Lru) evict(c *Cache) {
	fmt.Println("Evicting by lru strtegy")
}

lfu.go: Estratégia concreta

package main

import "fmt"

type Lfu struct {
}

func (l *Lfu) evict(c *Cache) {
	fmt.Println("Evicting by lfu strtegy")
}

cache.go: Context

package main

type Cache struct {
	storage      map[string]string
	evictionAlgo EvictionAlgo
	capacity     int
	maxCapacity  int
}

func initCache(e EvictionAlgo) *Cache {
	storage := make(map[string]string)
	return &Cache{
		storage:      storage,
		evictionAlgo: e,
		capacity:     0,
		maxCapacity:  2,
	}
}

func (c *Cache) setEvictionAlgo(e EvictionAlgo) {
	c.evictionAlgo = e
}

func (c *Cache) add(key, value string) {
	if c.capacity == c.maxCapacity {
		c.evict()
	}
	c.capacity++
	c.storage[key] = value
}

func (c *Cache) get(key string) {
	delete(c.storage, key)
}

func (c *Cache) evict() {
	c.evictionAlgo.evict(c)
	c.capacity--
}

main.go: Código cliente

package main

func main() {
	lfu := &Lfu{}
	cache := initCache(lfu)

	cache.add("a", "1")
	cache.add("b", "2")

	cache.add("c", "3")

	lru := &Lru{}
	cache.setEvictionAlgo(lru)

	cache.add("d", "4")

	fifo := &Fifo{}
	cache.setEvictionAlgo(fifo)

	cache.add("e", "5")

}

output.txt: Resultados da execução

Evicting by lfu strtegy
Evicting by lru strtegy
Evicting by fifo strtegy

Strategy em outras linguagens

Strategy em C# Strategy em C++ Strategy em Java Strategy em PHP Strategy em Python Strategy em Ruby Strategy em Rust Strategy em Swift Strategy em TypeScript