当前位置: 首页 > news >正文

【从零单排Golang】第八话:通过cache缓存模块示范interface该怎么用

和许多面向对象的编程语言一样,Golang也存在interface接口这样的概念。interface相当于是一个中间层,下游只需要关心interface实现了什么行为,利用这些行为做些业务级别事情,而上游则负责实现interface,把这些行为具象化。本文就来通过一个简单的缓存cache模块的实现,来示范一下Golanginterface该怎么用。

首先,从业务service角度而言,一个cache模块可能需要以下几种方法:

  • 获取缓存中的某个值
  • 缓存数据,加缓存时效
  • 删除缓存内容

那么这些个方法,就可以用一类叫Cacheinterface来表示:

type Cache interface {Get(key string) (interface{}, bool)Set(key string, value interface{})SetExpire(key string, value interface{}, expire time.Duration)Delete(key string)
}

其中,Get方法返回一个interface{}value,以及是否存在的bool标识;SetSetExpire表示无时限跟有时限的缓存行为;Delete表示删除缓存内容。整块Cache的接口定义也非常明显。

这样写有什么好处?如果你是下游业务服务的话,你只需要这样写就可以了。这里给一个同package下的测试用例代码:

func TestCache(t *testing.T) {k, v := "hello", "world"// Current()的实现,在下文慢慢解释var curCache Cache = Current()// set & get & deletecurCache.Set(k, v)cached, ok := curCache.Get(k)if !ok {t.Fatalf("cannot cache %s:%s", k, v)} else {t.Logf("got cached %s:%v (type: %s)", k, cached, reflect.TypeOf(cached).Name())}curCache.Delete(k)_, ok = curCache.Get(k)if ok {t.Fatalf("cannot delete %s:%s", k, v)} else {t.Logf("delete cached %s:%s", k, v)}// set expirecurCache.SetExpire(k, v, 1*time.Second)cached, ok = curCache.Get(k)if !ok {t.Fatalf("cannot cache %s:%s", k, v)} else {t.Logf("got cached %s:%v (type: %s)", k, cached, reflect.TypeOf(cached).Name())}time.Sleep(3 * time.Second)_, ok = curCache.Get(k)if ok {t.Fatalf("cannot expire %s:%s", k, v)} else {t.Logf("expired %s:%s", k, v)}
}

可以看到,我们指定的缓存对象curCache标识为一个Cache,是个接口定义,这样标识起来的话,下面的代码就可以正常使用GetSet之类的方法了。而更重要的是,下面的代码,不会因为Cache的具体实现变化而有所变化。举个例子,你有10个开源的缓存库,想定时切换Current() Cache背后的缓存对象实现,就算你再怎么换,只要用到缓存的代码标注缓存对象为Cache这个interface,并且interface的定义没有变化,那么使用缓存的代码就不需要动。这样,就彻底实现了缓存提供方和使用方的解耦,开发效率也会噌噌噌的上去。

既然提到了提供方Provider的概念,那在缓存的实现上,就可以走依赖注入控制反转的模式。假设某个Web服务有个本地缓存模块,在实现上,就可以考虑提供多个Cache接口的实现,同时在配置里指定默认的一种。这里,就以go-cache为例,做一个实现案例。

import ("github.com/patrickmn/go-cache""time"
)const (GoCacheDefaultExpiration = 10 * time.MinuteGoCacheCleanupInterval   = 15 * time.Minute
)type GoCache struct {c *cache.CachedefaultExpiration time.DurationcleanupInterval   time.Duration
}func (g *GoCache) Get(key string) (interface{}, bool) {return g.c.Get(key)
}func (g *GoCache) Set(key string, value interface{}) {g.c.Set(key, value, GoCacheDefaultExpiration)
}func (g *GoCache) SetExpire(key string, value interface{}, expire time.Duration) {if expire < 0 {expire = g.defaultExpiration}if expire > g.cleanupInterval {expire = g.cleanupInterval}g.c.Set(key, value, expire)
}func (g *GoCache) Delete(key string) {g.c.Delete(key)
}func NewGoCache() *GoCache {return &GoCache{c: cache.New(GoCacheDefaultExpiration, GoCacheCleanupInterval),defaultExpiration: GoCacheDefaultExpiration,cleanupInterval:   GoCacheCleanupInterval,}
}

当我们定义一个GoCachestruct,实现了Cache接口定义的所有行为,那么GoCache的实例,在Golang里,就能够被标识为一个Cache接口实例。NewGoCache方法,不仅是提供了一个GoCache的实例,而在业务层面,更是提供了一个Cache实例。因此,我们可以简单用一个map来管理所有的Cache的构造器,从而标识不同的缓存实现:

func provideGoCache() Cache {return NewGoCache()
}var cacheProviders = map[string]Cache{"go-cache": provideGoCache(),
}const (DefaultCacheProvider = "go-cache"
)func Get(provider string) Cache {c, ok := cacheProviders[provider]if !ok {return nil}return c
}func Default() Cache {return Get(DefaultCacheProvider)
}// 上文提到的样例代码,就用了这个方法拿到go-cache实现的Cache接口实例
func Current() Cache {return Default()
}

显而易见,通过这样的一个代码组织,不论是go-cache,抑或是其它的Cache实现,都可以集中管理并灵活取用。这,便是interfaceGolang编程中给我们带来的便利了。

相关文章:

【从零单排Golang】第八话:通过cache缓存模块示范interface该怎么用

和许多面向对象的编程语言一样&#xff0c;Golang也存在interface接口这样的概念。interface相当于是一个中间层&#xff0c;下游只需要关心interface实现了什么行为&#xff0c;利用这些行为做些业务级别事情&#xff0c;而上游则负责实现interface&#xff0c;把这些行为具象…...

解析从Linux零拷贝深入了解Linux-I/O(上)

本文将从文件传输场景以及零拷贝技术深究 Linux I/O 的发展过程、优化手段以及实际应用。前言 存储器是计算机的核心部件之一&#xff0c;在完全理想的状态下&#xff0c;存储器应该要同时具备以下三种特性&#xff1a; 速度足够快&#xff1a;存储器的存取速度应当快于 CPU …...

JavaScript系列之公有、私有和静态属性和方法

文章の目录一、公有属性、公有方法1、定义2、理解3、ES54、ES6二、私有属性、私有方法1、定义2、理解3、ES54、ES6三、静态属性、静态方法1、定义2、理解3、ES54、ES6写在最后一、公有属性、公有方法 1、定义 指的是所属这个类的所有对象都可以访问的属性&#xff0c;叫做公有…...

过滤器与拦截器

文章目录一、前言1、概述2、过滤器与拦截器异同2.1 简介2.2 异同2.3 总结3、Filters vs HandlerInterceptors二、过滤器1、概述2、生命周期2.1 生命周期概述2.2 基于函数回调实现原理3、自定义过滤器两种实现方式3.1 WebFilter注解注册3.2 过滤器&#xff08;配置类注册过滤器&…...

spring boot 和cloud 版本升级

spring boot 和cloud 版本对应 背景&#xff1a;原来一直用的版本是Hoxton.SR12 2.3.10.RELEASE&#xff08;SR12一路升&#xff0c;几乎没有影响&#xff0c;不需要测试&#xff0c;但是换大版本就有点担心&#xff09; 去年2022年底黑鸭子报漏洞把springboot&#xff0c;clou…...

untiy 录制网络摄像头视频并保存到本地文件

网络摄像头使用的是海康威视的&#xff0c;关于如何使用Ump插件播放海康威视rtsp视频流&#xff0c;请参考我的这篇文章 内部有ump插件的下载链接 untiy接入 海康威视网络摄像头 录屏使用的插件是 AVPro movieCapture 4.6.3版&#xff0c; 插件和完整工程的下载链接放在本文的…...

微服务架构设计模式-(15)部署

关联概念 流程 将软件投入到生产环境 架构 软件运行的环境结构 生产环境四个关键功能 服务管理接口 使开发人员能够创建、更新和配置服务 运行时服务管理 确保始终运行一定数量的服务实例非中断更新 监控 让开发人员了解服务情况&#xff0c;包括日志文件和各种应用指标可观…...

Redis:数据结构

简单动态字符串SDS Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组&#xff0c;以下简称C字符串)&#xff0c;而是自己构 建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型&#xff0c;并将SDS用作Redis的默认字符 串表示。 SDS 的实现…...

2.18 设置language和中文输入法

文章目录一&#xff1a;设置language二&#xff1a;设置中文输入法一&#xff1a;设置language nvidia的开发板上默认只有English&#xff0c;需要点击如下管理&#xff1a; 接着进入如下界面&#xff1a; 此时图中的“汉语&#xff08;中国&#xff09;”应该是没有的&…...

图解LeetCode——剑指 Offer 28. 对称的二叉树

一、题目 请实现一个函数&#xff0c;用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样&#xff0c;那么它是对称的。 二、示例 2.1> 示例 1&#xff1a; 【输入】root [1,2,2,3,4,4,3] 【输出】true 2.2> 示例 2&#xff1a; 【输入】root [1,2,2,nul…...

Qt Desginer布局方法

首先将我们需要的控件拖拽到一个合适的位置&#xff0c;该例子中用到了两个label&#xff0c;两个lineEdit和两个pushButton。 然后我们需要利用弹簧来控制控件到控件之间的距离以及控件到窗体边界的距离&#xff0c;因为这里只有一组控件&#xff08;两个label&#xff0c;两个…...

C/C++、Java、Python的比较及学习(3)

函数间的值传递与地址传递 值传递方式&#xff1a;指主调函数把实参的值赋给形参。 在这种传递方式下&#xff0c;主调函数中的实参地址与被调函数中的形参地址是相互独立的。 函数被调用时&#xff0c;系统为形参变量分配内存单元&#xff0c;并将实参的值存入到对应形参的内存…...

智慧校园建设方案

第一章、 智慧教学 6.1. 校本资源库 提供校本资源管理功能&#xff0c;实现学校内的教学资源的共建共享&#xff0c;促进教师之间的交流学习&#xff0c;提升学校的整体教学水平。在本系统中学校可以统一采购资源接入到校本资源库中供教师下载使用&#xff0c;教师也可以将…...

ARM uboot 源码分析5 -启动第二阶段

一、start_armboot 解析6 1、console_init_f (1) console_init_f 是 console&#xff08;控制台&#xff09;的第一阶段初始化。_f 表示是第一阶段初始化&#xff0c;_r 表示第二阶段初始化。有时候初始化函数不能一次一起完成&#xff0c;中间必须要夹杂一些代码&#xff0c;…...

【ip neigh】管理IP邻居( 添加ARP\NDP静态记录、删除记录、查看记录)

一、邻居管理存在状态 1、NUD_NONE&#xff1a; 初始状态。当一个新的路由缓存条目被创建时&#xff0c;arp_bind_neighbour()函数被调用.如果找不到相匹配的ARP缓存条目, neigh_alloc()将创建一个新的ARP缓存条目并设置状态为NUD_NONE. 2、NUD_INCOMPLETE&#xff1a;未完成状…...

Java程序员线上排查问题神器-Arthas

文章目录前言一、Arthas是什么&#xff1f;二、快速入门1.下载2.如何运行三、常用命令1.dashboard2.trace总结前言 最近公司项目版本迭代升级&#xff0c;在开发新需求导致没什么时间写博客。 在开发需求的过程中&#xff0c;我写了一个接口&#xff0c;去批量调内部已经写好…...

上市公司企业持续创新能力、创新可持续性(原始数据+计算代码+计算结果)(2008-2021年)

数据来源&#xff1a;自主计算 时间跨度&#xff1a;2008-2021年 区域范围&#xff1a;沪深A股上市公司 指标说明&#xff1a; 参考何郁冰&#xff08;2017&#xff09;[1]的做法&#xff0c;将持续创新作为独立研究变量&#xff0c;同时采用创新投入指标(研发经费) 和创新…...

华为OD机试 - 考古学家(JS)

考古学家 题目 有一个考古学家发现一个石碑 但是很可惜 发现时其已经断成多段 原地发现N个断口整齐的石碑碎片 为了破解石碑内容 考古学家希望有程序能帮忙计算复原后的石碑文字组合数 你能帮忙吗 备注: 如果存在石碑碎片内容完全相同,则由于碎片间的顺序不影响复原后的碑…...

Leetcode.2100 适合打劫银行的日子

题目链接 Leetcode.2100 适合打劫银行的日子 Rating &#xff1a; 1702 题目描述 你和一群强盗准备打劫银行。给你一个下标从 0开始的整数数组 security&#xff0c;其中 security[i]是第 i天执勤警卫的数量。日子从 0开始编号。同时给你一个整数 time。 如果第 i天满足以下所…...

linux ubuntu查日志信息以及错误排查

目录 一、linux的日志文件 1、常用日志文件 2、其他日志文件 二、历史日志的查看 1、查看Logrotate的配置信息 2、查看日志配置 一、linux的日志文件 Linux系统中最有趣的(可能也是最重要的)目录之一是/var/log。根据文件系统层次结构标准&#xff0c;在系统中运行的大多数…...

ACO蚁群算法优化KELM核极限学习机(ACO-KELM)回归预测MATLAB代码 代码注释清...

ACO蚁群算法优化KELM核极限学习机&#xff08;ACO-KELM&#xff09;回归预测MATLAB代码 代码注释清楚。 main为主程序&#xff0c;可以读取EXCEL数据。 很方便&#xff0c;容易上手。 &#xff08;电厂运行数据为例&#xff09;老铁们今天带大家玩点硬核的——用蚂蚁找食物的…...

告别依赖烦恼:在Windows上使用vcpkg一站式部署Protobuf C++开发环境

1. 为什么选择vcpkg管理Protobuf依赖&#xff1f; 在Windows上进行C开发时&#xff0c;最让人头疼的莫过于第三方库的依赖管理。我至今还记得第一次手动编译Protobuf时的崩溃经历——下载源码、配置编译选项、解决依赖冲突&#xff0c;整个过程花了整整两天时间。直到发现了vcp…...

TP6.0.2环境搭建常见问题排查:从OCI8报错到Composer镜像配置的完整解决方案

TP6.0.2环境搭建全流程排障指南&#xff1a;从OCI8报错到镜像加速的实战解决方案 每次打开终端准备大干一场时&#xff0c;那些突如其来的红色报错信息总能让开发者心跳加速。上周我在客户现场部署ThinkPHP6时&#xff0c;就遭遇了经典的"Module oci8 already loaded&quo…...

Phi-3-Mini-128K长文本处理巅峰展示:完整技术白皮书摘要与问答

Phi-3-Mini-128K长文本处理巅峰展示&#xff1a;完整技术白皮书摘要与问答 你有没有遇到过这样的情况&#xff1f;面对一份动辄几十页、几万字的技术文档或研究报告&#xff0c;想要快速抓住核心要点&#xff0c;或者查找某个具体的细节&#xff0c;感觉就像大海捞针。传统的阅…...

如何快速实现Blender模型批量导入:PSK/PSA插件终极自动化指南

如何快速实现Blender模型批量导入&#xff1a;PSK/PSA插件终极自动化指南 【免费下载链接】io_scene_psk_psa A Blender plugin for importing and exporting Unreal PSK and PSA files 项目地址: https://gitcode.com/gh_mirrors/io/io_scene_psk_psa Blender PSK/PSA插…...

春联生成模型-中文-base生成效果展示:多组祝福词对联作品集锦

春联生成模型-中文-base生成效果展示&#xff1a;多组祝福词对联作品集锦 1. 模型效果概览 春节将至&#xff0c;家家户户都开始准备贴春联。传统春联创作需要深厚的文学功底&#xff0c;而如今AI技术让这一过程变得简单有趣。春联生成模型-中文-base是达摩院AliceMind团队基…...

ESS、RSS、TSS傻傻分不清?5分钟搞懂机器学习回归模型的核心指标

ESS、RSS、TSS&#xff1a;用生活案例拆解机器学习回归模型的三大核心指标 每次看到天气预报说"明天降水概率70%"&#xff0c;你是否好奇这个数字是怎么算出来的&#xff1f;这背后其实和机器学习模型评估指标有着异曲同工之妙。今天我们就用生活中常见的预测场景&am…...

用生活案例理解镜像法:从避雷针到无线充电的电磁场等效原理

用生活案例理解镜像法&#xff1a;从避雷针到无线充电的电磁场等效原理 想象一下雷雨天气时&#xff0c;高楼顶端的避雷针如何将闪电引入大地&#xff1b;或者当你把手机放在无线充电板上时&#xff0c;能量如何穿过空气传递到设备内部。这些看似不同的现象背后&#xff0c;都隐…...

Nanbeige 4.1-3B惊艳效果:文字逐字蹦出+像素方块光标动效演示

Nanbeige 4.1-3B惊艳效果&#xff1a;文字逐字蹦出像素方块光标动效演示 1. 复古像素风AI对话新体验 在当今AI交互界面普遍追求极简风格的背景下&#xff0c;Nanbeige 4.1-3B带来了一股清新的复古风潮。这套专为4.1-3B模型设计的像素游戏风对话前端&#xff0c;将AI对话体验提…...

Matlab综合能源系统优化代码:光热电站与ORC建模求解及9节点电网等多网仿真分析

Matlab综合能源系统优化代码 考虑光热电站&#xff08;CSP电站&#xff09;和ORC的综合能源系统优化的建模求解 程序中包含了新能源发电、ORC循环等&#xff0c;以运行成本、碳排放成本、弃风弃光惩罚成本等为目标函数&#xff0c;基于9节点电网、6节点气网、8节点热网、4节点冷…...