策略模式是一种行为型设计模式。通过策略模式,可以在运行时修改一个对象的行为。

接下来仍然是通过例子来了解策略模式。比如说内存缓存,这是我们在开发中经常使用的东西,大家应该都有一定的了解,接下来就用内存缓存来说明下如何使用策略模式。

向内存里存东西对于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做任何调整。

现在捋一下什么时候使用策略模式:

  1. 当一个对象需要提供不同的行为,而又不想在运行时修改对象时
  2. 当想在运行时选择不同的行为而又不想写大量的条件语句时
  3. 当为同一种行为准备了不同的算法时

下面是策略模式的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!!

GoLang设计模式15 - 策略模式的更多相关文章

  1. python设计模式之策略模式

    每次看到项目中存在大量的if else代码时,都会心生一丝不安全感. 特别是产品给的需求需要添加或者更改一种if条件时,生怕会因为自己的疏忽而使代码天崩地裂,哈哈,本文的目的就是来解决这种不安全感的, ...

  2. 设计模式:策略模式(Strategy)

    定   义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...

  3. PHP设计模式之策略模式

    前提: 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查 找.排序等,一种常用的方法是硬编码(Hard Cod ...

  4. JavaScript设计模式之策略模式(学习笔记)

    在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...

  5. c++设计模式15 --组合模式

    今天研究了一下设计模式15 组合模式 本人是菜鸟一枚,所以一开始完全不懂组合究竟是什么意思.先上图一张,树形结构图: 文档说,如果想做出这样的结构,通常考虑组合模式.那是为什么呢?现在让我们看一下组合 ...

  6. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  7. JavaScript设计模式之策略模式

    所谓"条条道路通罗马",在现实中,为达到某种目的往往不是只有一种方法.比如挣钱养家:可以做点小生意,可以打分工,甚至还可以是偷.抢.赌等等各种手段.在程序语言设计中,也会遇到这种类 ...

  8. 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查

    原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...

  9. [design-patterns]设计模式之一策略模式

    设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不 ...

随机推荐

  1. 好未来数据中台 Node.js BFF实践(一):基础篇

    好未来数据中台 Node.js BFF实践系列文章列表: 基础篇 实战篇(TODO) 进阶篇(TODO) 好未来数据中台的Node.js中间层从7月份开始讨论可行性,截止到9月已经支持了4个平台,其中 ...

  2. 常见错误0xCCCCCCCCC 读取字符串的字符时出错及其引申。

    问题描述在一个函数调用中,使用二级指针作为函数参数,传递一个字符串指针数组,但是在访问的时候,却出现了运行时错误,具体表现为"0xCCCCCCCC 读取字符串的字符时出错". 第一 ...

  3. 《手把手教你》系列技巧篇(三十)-java+ selenium自动化测试- Actions的相关操作下篇(详解教程)

    1.简介 本文主要介绍两个在测试过程中可能会用到的功能:Actions类中的拖拽操作和Actions类中的划取字段操作.例如:需要在一堆log字符中随机划取一段文字,然后右键选择摘取功能. 2.拖拽操 ...

  4. 一个关于MySQL指定编码实现的小坑

    写在前面 环境:MySQL5.7+,MySQL数据库字符编码实现为utf8,表也为utf8 场景:微信授权获取用户信息(包括昵称)并保存到数据库,有的用户成功了,少数用户却失败了 那么为什么会失败呢? ...

  5. 【转载】如何从零开始开发一款嵌入式产品(20年的嵌入式经验分享学习,来自STM32神舟系列开发板设计师的总结

    [好文章值得分享,摘自作者:jesse] 来源:www.armjishu.com作者:jesse转载请注明出处 我的另一篇文章:<STM32嵌入式入门必看之文章-----介绍非常详细!(学STM ...

  6. Linux常用命令,查看树形结构、删除目录(文件夹)、创建文件、删除文件或目录、复制文件或目录(文件夹)、移动、查看文件内容、权限操作

    5.查看树结构(tree) 通常情况下系统未安装该命令,需要yum install -y tree安装 直接使⽤tree显示深度太多,⼀般会使⽤ -L选项⼿⼯设定⽬录深度 格式:tree -L n [ ...

  7. ScatterLayout:分散布局在py中的引用

    """ ScatterLayout:分散布局 """ from kivy.app import App from kivy.uix.scat ...

  8. Asp.net Core C#进行筛选、过滤、使用PredicateBuilder进行动态拼接lamdba表达式树并用作条件精准查询,模糊查询

    在asp.net core.asp.net 中做where条件过滤筛选的时候写的长而繁琐不利于维护,用PredicateBuilder进行筛选.过滤.LInq配合Ef.core进行动态拼接lamdba ...

  9. 2021.8.11考试总结[NOIP模拟36]

    T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...

  10. Linux C语言链表详细分析

    链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用.链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节 ...