策略模式是一種行為型設計模式。通過策略模式,可以在運行時修改一個對象的行為。
接下來仍然是通過例子來了解策略模式。比如說內存緩存,這是我們在開發中經常使用的東西,大家應該都有一定的了解,接下來就用內存緩存來說明下如何使用策略模式。
向內存里存東西對於GoLang來說算是比較簡單的事情,通過Map就可以做到,不過還是建議創建一個Cache struct來稍稍封裝一下。不過我們都知道,內存緩存占用的空間是有上限的。當快達到上限時,就需要清理一下緩存中已有的內容。如下是清理緩存的一些常見的算法:
- LRU(Least Recently Used):清理最近使用的最少的那些緩存數據
- FIFO(First In First Out):清理最早放入緩存的那些數據
- LFU(Least Frequently Used):清理使用頻率最低的那部分數據
現在的問題是如何將Cache和清理算法解耦,這樣在運行時就可以調整清理緩存的算法了。但也要注意,在添加新的清理算法時,不應該改動Cache。這時候就需要用到策略模式了。策略模式建議為相同業務的各種算法創建一個算法組,然后將每種算法都封裝起來,使之有相同的接口,並且不同算法之間可以互換。清理緩存的算法的接口就可以命名為:evictionAlgo。
然后將evictionAlgo接口嵌入Cache中就可以了。
不同於讓Cache直接自己繼承evictionAlgo接口,現在可以通過evictionAlgo接口來組裝不同的清理算法。因為evictionAlgo是一個接口,這樣在運行的時候就可以將之賦值為LRU、FIFO或LFU,而不需要對Cache struct做任何調整。
現在捋一下什么時候使用策略模式:
- 當一個對象需要提供不同的行為,而又不想在運行時修改對象時
- 當想在運行時選擇不同的行為而又不想寫大量的條件語句時
- 當為同一種行為准備了不同的算法時
下面是策略模式的UML類圖:
這里是我們當前這個內存緩存案例的UML圖:
具體代碼如下:
evictionAlgo.go:
type evictionAlgo interface {
evict(c *cache)
}
lru.go:
import "fmt"
type lru struct {
}
func (l *lru) evict(c *cache) {
fmt.Println("Evicting by lru strategy")
}
fifo.go:
import "fmt"
type fifo struct {
}
func (l *fifo) evict(c *cache) {
fmt.Println("Evicting by fifo strategy")
}
lfu.go
import "fmt"
type lfu struct {
}
func (l *lfu) evict(c *cache) {
fmt.Println("Evicting by lfu strategy")
}
cache.go
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
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")
}
執行后的輸出內容為:
Evicting by lfu strategy Evicting by lru strategy Evicting by fifo strategy
代碼已上傳至GitHub: zhyea / go-patterns / strategy-pattern
END!!
