Глянь мій новий курс по Git! Привіт! Глянь мій новий курс по Git! Привіт! Глянь мій новий курс по Git на GitByBit.com! Привіт! Хочеш класно освіжити Git? Глянь мій новий курс на GitByBit.com!
Стратегія

Стратегія на Go

Стратегія — це поведінковий патерн, який виносить набір алгоритмів у власні класи і робить їх взаємозамінними.

Інші об’єкти містять посилання на об’єкт-стратегію та делегують їй роботу. Програма може підмінити цей об’єкт іншим, якщо потрібен інший спосіб вирішення завдання.

Концептуальний приклад

Уявіть, що ви розробляєте «In-Memory-Cache». Оскільки він розташований всередині пам’яті, його розмір обмежений. Щойно він вщент заповниться, якісь записи доведеться прибрати, аби звільнити простір. Цю функцію можна реалізувати завдяки декільком алгоритмам, найпопулярніші серед них:

  • Найбільш давно використовувалися (Least Recently Used — LRU): прибирає запис, який використовувався найбільш давно.
  • «Першим прийшов, першим пішов» (First In, First Out — FIFO): прибирає запис, який був створений раніше за інші.
  • Найменш часто використовувалися (Least Frequently Used — LFU): прибирає запис, який використовувався найменш часто.

Проблема полягає в тому, щоб відокремити кеш від цих алгоритмів для можливості їх заміни «на ходу». Крім цього, клас кешу мусить не змінюватися при додаванні нового алгоритму.

У такій ситуації нам допоможе патерн Стратегія. Він передбачає створення сімейства алгоритмів, кожен з яких має свій клас. Всі класи застосовують однаковий інтерфейс, що робить алгоритми взаємозамінними всередині цього сімейства. Назвемо цей загальний інтерфейс evictionAlgo.

Тепер основний клас нашого кеша включатиме у себе evictionAlgo. Замість прямої реалізації всіх типів алгоритмів витіснення всередині самого себе, наш клас передаватиме їх в evictionAlgo. Оскільки це інтерфейс, ми можемо безпосередньо під час виконання програми змінювати алгоритм на LRU, FIFO, LFU без змін у класі кеша.

evictionAlgo.go: Інтерфейс стратегії

package main

type EvictionAlgo interface {
	evict(c *Cache)
}

fifo.go: Конкретна стратегія

package main

import "fmt"

type Fifo struct {
}

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

lru.go: Конкретна стратегія

package main

import "fmt"

type Lru struct {
}

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

lfu.go: Конкретна стратегія

package main

import "fmt"

type Lfu struct {
}

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

cache.go: Контекст

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: Клієнтський код

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: Результат виконання

Evicting by lfu strtegy
Evicting by lru strtegy
Evicting by fifo strtegy
На основі: Golang By Example

Стратегія іншими мовами програмування

Стратегія на C# Стратегія на C++ Стратегія на Java Стратегія на PHP Стратегія на Python Стратегія на Ruby Стратегія на Rust Стратегія на Swift Стратегія на TypeScript