1. design-patterns/

golang 策略模式讲解和代码示例

·273 字·2 分钟· loading
设计模式 设计模式 golang
demo007x
作者
demo007x
设计模式 - This article is part of a series.
Part : This Article

Go 策略模式讲解和代码示例
#

策略是一种行为设计模式, 它将一组行为转换为对象, 并使其在原始上下文对象内部能够相互替换。

原始对象被称为上下文, 它包含指向策略对象的引用并将执行行为的任务分派给策略对象。 为了改变上下文完成其工作的方式, 其他对象可以使用另一个对象来替换当前链接的策略对象。

概念示例
#

思考一下构建内存缓存的情形。 由于处在内存中, 故其大小会存在限制。 在达到其上限后, 一些条目就必须被移除以留出空间。 此类操作可通过多种算法进行实现。 一些流行的算法有:

  • 最少最近使用 (LRU): 移除最近使用最少的一条条目。
  • 先进先出 (FIFO): 移除最早创建的条目。
  • 最少使用 (LFU): 移除使用频率最低一条条目。

问题在于如何将我们的缓存类与这些算法解耦, 以便在运行时更改算法。 此外, 在添加新算法时, 缓存类不应改变。

这就是策略模式发挥作用的场景。 可创建一系列的算法, 每个算法都有自己的类。 这些类中的每一个都遵循相同的接口, 这使得系列算法之间可以互换。 假设通用接口名称为 eviction­Algo移除算法 。

现在, 我们的主要缓存类将嵌入至 eviction­Algo接口中。 缓存类会将全部类型的移除算法委派给 eviction­Algo接口, 而不是自行实现。 鉴于 eviction­Algo是一个接口, 我们可在运行时将算法更改为 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
	macCapacity  int
}

// 初始化的时候将策略注入到 cache 中
func initCache(e EvictionAlgo) *Cache {
	storage := make(map[string]string)
	return &Cache{
		storage:      storage,
		evictionAlgo: e,
		capacity:     0,
		macCapacity:  2,
	}
}

// 动态修改策略
func (c *Cache) setEvictionAlgo(e EvictionAlgo) {
	c.evictionAlgo = e
}

func (c *Cache) add(key, value string) {
	// 如果缓存中的容量等于了最大容量,则需要执行策略来移除 s
	if c.capacity == c.macCapacity {
		c.evict()
	}
	c.capacity++
	c.storage[key] = value
}

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

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

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
设计模式 - This article is part of a series.
Part : This Article

Related

golang 状态模式讲解和代码示例
设计模式 设计模式 golang
状态是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为。该模式将与状态相关的行为抽取到独立的状态类中, 让原对象将工作委派给这些类的实例, 而不是自行进行处理。
golang 单例模式讲解和代码示例
设计模式 设计模式 golang
单例是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。单例拥有与全局变量相同的优缺点。 尽管它们非常有用, 但却会破坏代码的模块化特性。在某些其他上下文中, 你不能使用依赖于单例的类。 你也将必须使用单例类。 绝大多数情况下, 该限制会在创建单元测试时出现。
golang 备忘录模式讲解和代码示例
设计模式 设计模式 golang
备忘录是一种行为设计模式, 允许生成对象状态的快照并在以后将其还原。备忘录不会影响它所处理的对象的内部结构, 也不会影响快照中保存的数据。