Go语言必知必会100问题-06 生产者端接口

news2024/12/26 0:44:06
生产者端接口

Go语言必知必会100问题-05 接口污染中介绍了程序中使用接口是有价值的。在编码的时候,接口应该放在哪里呢?这是Go开发人员经常有误解的一个问题,本文将深入分析该问题。

在深入探讨问题之前,先对提及的术语做一个定义说明,确保我们对其有清晰的理解。

  • 生产者端:接口定义与具体实现在同一个包中,称这种为生产者端接口。像下图所示,接口的定义和具体实现都在foo包中,调用客户端代码在bar包中。

在这里插入图片描述

  • 消费者端:接口定义与具体实现不在相同的包中,而是定义在调用的客户端代码所在的包中,称这种为消费者端接口。如下图所示,接口定义在使用方包bar中。

在这里插入图片描述

在生产者端定义接口,与具体实现放在一起,这是具有C#或Java背景语言的人惯用写法。然而,在Go语言中,在大多数情况下,我们不应该采用这种写法。下面通过一个示例进行说明。

示例中,我们创建一个特定的包来存储和查询客户数据。同时在该包中定义一个接口,所有对客户数据的操作都通过接口来实现。对应到前面,这种实现就是生产者端接口。

package store

type CustomerStorage interface {
        StoreCustomer(customer Customer) error
        GetCustomer(id string) (Customer, error)
        UpdateCustomer(customer Customer) error
        GetAllCustomers() ([]Customer, error)
        GetCustomersWithoutContract() ([]Customer, error)
        GetCustomersWithNegativeBalance() ([]Customer, error)
}

对于上面在生产者端创建接口,并对外暴露这个接口。可能认为有很好的理由这样做,我们可能会说,1.这样可以将客户端代码与实际实现分离,2. 在测试的时候,调用方很方便Mock一个假的接口实现进行测试。但是,这不是Go中的最佳实践。

正如Go语言必知必会100问题-05 接口污染所提到的,与具有显示实现接口的语言相比,Go中通过隐式实现接口,这会带来一些变化,像其它语言惯用的生产者端接口在Go语言中并不是最佳实践。在大多数情况下,应该遵循Go语言必知必会100问题-05 接口污染提到的原则:应该发现抽象而不是创建抽象。这意味着生产者不能为所有客户端强制一个给定的抽象。相反,由客户端决定它是否需要某种形式的抽象。然后确定最适合它需要的抽象级别。

对于上述示例,也许客户端A不会对解耦它的代码感兴趣,也许客户端B想要解耦它的代码,但只对 GetAllCustomers 方法感兴趣。在这种情况下,可以使用单个方法创建一个接口,引用外部包中的 Customer 结构体。

package client

type customersGetter interface {
        GetAllCustomers() ([]store.Customer, error)
}

从包组织引用关系来看,客户端和存储两个包关系如下图。需要注意几点:

  • 由于 customersGetter 接口仅在客户端包中使用,因此该接口可以保持不导出。
  • 咋一看,下图看起来像存在循环依赖。但是,由于隐式满足接口,存储与客户端之间没有循环依赖关系。这也是为什么这种方法在具有显示实现的语言中并不总是可行的原因。

在这里插入图片描述

采用在客户端中定义接口的关键点是客户端可以根据需要定义最准确的抽象(像customersGetter只有一个方法),契合接口隔离原则(SOLID中的I),该原则指出不应强迫任何客户端依赖它不使用的方法。因此,在这种情况下,最好的方法是在生产者端公开具体实现(方法可导出),让客户端决定如何使用它以及是否需要抽象。

本文提到了生产者端接口和消费者端接口两个概念,前面分析了消费者端接口,为了完整性,这里对生产者端接口也做点分析。生产者端接口有时候会在标准库中遇到,例如encoding子包中定义了实现的接口,如encoding/json、encoding/binary. 采用这种方式错了吗?前面不是说Go中不推荐生产者端接口吗? 没有错,在这种情况下,encoding包中定义的抽象在标准库中使用,语言设计者知道预先创建这种抽象是有价值的。这满足Go语言必知必会100问题-05 接口污染中的讨论:如果你认为抽象在想象的将来可能有用,但是不能证明这个抽象时有效的,就不要创建抽象。

因此,在大多数情况下,Go语言中的接口应该位于消费者端。但是,在特定情况下,例如,当我们知道(不是预想)抽象对消费者有帮助时,我们可能希望将其放在生产者端。如果要这样做,应该努力让接口尽可能地最小化(接口中的方法仅可能少),像encoding/json中定义的Marshaler接口只包含1个方法,这样增加它的可重用潜力并使其更容易组合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1472264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用Inno Setup制作Unity构建程序的Windows安装程序

1. 准备 (1)准备好Unity构建的程序集合 必须包括: Data文件夹(xxx_Data) Mono文件夹(MonoBleedingEdge) 打包的应用程序文件(xxx.exe) Unity播放器dll文件&#xff…

mac flutter 配置

下载Flutter Sdk 直接访问官网无法下载,需要访问中国镜像下载 Flutter SDK 归档列表 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter Start building Flutter Android apps on macOS - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 下载后解压…

HCIA-Datacom实验指导手册:5.1 实验一:FTP SFTP TFTP 基础配置实验

HCIA-Datacom实验指导手册:5.1 实验一:FTP 基础配置实验 一、实验介绍:二、实验拓扑:三、实验目的:四、配置步骤:步骤 1 设备基础配置步骤 2 在 Router 上配置 FTP 和SFTP服务器功能及参数步骤 3 配置本地 …

大厂经验谈之OKR目标管理

前言 这是大厂经验谈系列第一篇文章,来看看互联网公司是如何制定和管理目标的。OKR是目前互联网公司经常采用的目标管理工具,最开始也是由国外著名公司推崇,比如Google、微软、亚马逊等,后面才逐步引入国内。既然是工具就有用得好和不好的地方,很多团队仍然把OKR当做KPI来…

【人工智能高频面试题--基本篇】

🚀 作者 :“码上有前” 🚀 文章简介 :人工智能高频面试题 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 人工智能高频面试题--基本篇 1.深度学习和过往的神经网络训练方法有什么区别?列举…

2024年 前端JavaScript入门到精通 第四天 笔记

4.1 函数的基本使用以及封装练习 ★ 函数命名规范 4.2 函数的参数以及默认参数 函数的灵魂!!! 4.3 函数封装数组求和案例 4.4 函数返回值return 4.5 函数返回值细节以及上午总结 4.6 函数返回值案例-求最大值和最 4.7 函数复习以及断点进入函…

php脚本输出中文在浏览器中显示乱码

问题说明 这个问题一般出现在较低版本的php中,原因是php和浏览器的字符解析方式不对应 ,导致中文字符被错误解析成乱码 (注,此处的php版本任意切换是依赖于小皮面板(phpstudy)实现的,感兴趣可以…

132 Linux 系统编程9 ,IO操作,lseek 函数,truncate函数,查看文件的表示形式

一 lseek 函数 函数说明:此函数用于文件偏移 Linux中可使用系统函数lseek来修改文件偏移量(读写位置) 每个打开的文件都记录着当前读写位置,打开文件时读写位置是0,表示文件开头,通常读写多少个字节就会将读写位置往后移多少个字…

2024国际生物发酵展览会全面揭秘-西尼尔过程控制

参展企业检查 西尼尔(南京)过程控制有限公司成立于2007年,坐落于美丽的六朝古都南京,占地面积20000平方米,现有员工130人,其中70%为本科及以上学历,高级、中级专业技术人员占比30%以上。 公司为…

[NOIP2011 普及组] 数字反转

AC代码&#xff1a; #include<iostream>using namespace std;int main() {long long n;cin >> n;long long temp n;long long sum 0;while(temp ! 0){int c temp % 10;sum sum * 10 c;temp temp / 10;}printf("%lld",sum);return 0; }

BUUCTF第二十四、二十五题解题思路

目录 第二十四题CrackRTF 第二十五题[2019红帽杯]easyRE1 第二十四题CrackRTF 查壳 无壳&#xff0c;32位&#xff0c;用32位IDA打开&#xff0c;打开后的main函数很短&#xff0c;可以找到一句“jmz _main_0”——跳转到 _main_0&#xff0c;说明真正的主函数是_main_0&am…

Rem 自适应原理与应用

前言 移动端适配有很多方案&#xff0c;这篇文章将根据 rem 自适应的原理进行讲解&#xff0c;接下来跟着作者的思路一起来看看吧&#xff01; 原理 在搞清楚 rem 适配之前&#xff0c;我们先来了解一下什么是 rem&#xff1f; rem 是一种相对长度单位&#xff0c;它相对于根…

Mysql学习之事务日志undolog深入剖析

Undo log redo log 是事务持久性的保证&#xff0c;undo log是事务原子性的保证。在事务中更新数据的前置操作其实是要先写入一个undo log。 如何理解undo 日志&#xff1f; 事务需要保证原子性&#xff0c;也就是事务中的操作要么全部完成&#xff0c;要么什么也不做。但有时…

SQLServer 格式化数据的方法

格式化数据一般考虑使用FORMAT 或者CONVERT ​​​​​​​函数&#xff0c;FORMAT 函数是在 SQL Server 2012 中引入的&#xff0c;如果你使用的是较早版本的 SQL Server&#xff0c;则可能需要考虑使用其他方法&#xff0c;如 CONVERT 函数。 在 SQL Server 中&#xff0c;FO…

动态规划--状态转移

解码方法 1.题目 2.思路 1&#xff09;我们定义一个数组dp&#xff0c;其中dp[i]表示字符串s的前i个字符的解码方法总数。初始化时&#xff0c;dp[0]为1&#xff0c;因为空字符串有一种解码方式。dp[1]的值取决于第一个字符是否是0&#xff0c;如果不是0&#xff0c;则有一种…

Unity—MVC分层开发思想

每日一句&#xff1a;当你不努力的时候&#xff0c;天赋就会一点一点被收回 目录 MVC分层开发思想 MVC是什么 MVC的开发步骤 案例&#xff1a;点击按钮实现金币进行添加&#xff0c;并且把金币记录到JSON里 MVC模式实现 背包系统基础代码 背包项目实现步骤 MVC分层开发思…

第十三天-mysql交互

目录 1.安装MySQL connector 方式1&#xff1a;直接安装 方式2&#xff1a;下载 2.创建链接 3.游标Cursor 4.事务控制 5. 数据库连接池 1. 使用 6.循环执行SQL语句 不了解mysql的可以先了解mysql基础 1.安装MySQL connector 1. MySQL connector 是MySQL官方驱动模块…

VirtualBox+Vagrant安装linux

一、VirtualBox安装 VirtualBox官网&#xff1a;Oracle VM VirtualBox 这里采用VirtualBox--7.0.0 版本 二、Vagrant安装 Vagrant官网&#xff1a;Vagrant by HashiCorp Vagrant镜像仓库&#xff1a;Discover Vagrant Boxes - Vagrant Cloud 这里采用Vagrant--2.4.1版本 在…

Python从入门到精通指南【第101篇—入门到精通】【文末送书-24】

文章目录 Python从入门到精通指南第一步&#xff1a;入门基础1.1 安装Python1.2 Hello World1.3 变量和数据类型1.4 控制流程 第二步&#xff1a;深入学习2.1 函数和模块2.2 列表、元组和字典2.3 文件操作 第三步&#xff1a;高级主题3.1 面向对象编程3.2 异常处理3.3 正则表达…

猫头虎分享已解决Bug || 无效的请求参数:InvalidRequestException

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …