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

生产者端接口

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

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

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

在这里插入图片描述

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

在这里插入图片描述

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

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

package storetype CustomerStorage interface {StoreCustomer(customer Customer) errorGetCustomer(id string) (Customer, error)UpdateCustomer(customer Customer) errorGetAllCustomers() ([]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 clienttype 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.mzph.cn/news/704387.shtml

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

相关文章

MySQL(2/3)

select和别名的使用 主要是用以查询数据 语法:select 字段 from 库名 -- *代表全部字段 select * from student; -- 可以查询多个字段,并使用as起别名,as可以省略 select id as bbb ,name as hhh from student; -- 可以使用函数concat(a,b…

新版Java面试专题视频教程——虚拟机篇②

新版Java面试专题视频教程——虚拟机篇② 3 垃圾收回3.1 简述Java垃圾回收机制?(GC是什么?为什么要GC)3.2 对象什么时候可以被垃圾器回收3.2.1 引用计数法3.2.2 可达性分析算法 3.3 JVM 垃圾回收算法有哪些?——4种3.3…

Python实现DAS单点登录

❇️ 流程 进入登录页面 (DAS验证的登录页面) 获取验证码图像,百度OCR识别 登录 🏞️ 环境 Windows 11 Python 3.12 PyCharm 2023 🧵 准备工作 安装必要依赖库 bs4 Jupyter 推荐安装 Jupyter(Anaco…

数学建模【相关性模型】

一、相关性模型简介 相关性模型并不是指一个具体的模型,而是一类模型,这一类模型用来判断变量之间是否具有相关性。一般来说,分析两个变量之间是否具有相关性,我们根据数据服从的分布和数据所具有的特点选择使用pearson&#xff…

Linux系统——Nginx小总结

目录 一、影响用户体验的因素 二、网络连接——Apache/Nginx服务请求过程 三、I/O模型——Input/Output模型 1.同步/异步 2.阻塞/非阻塞 3.同步异步/阻塞非阻塞组合 四、Nginx用法 一、影响用户体验的因素 客户端硬件配置客户端网络速率客户端与服务端距离服务端网络速…

容器库(12)-std::unordered_multiset

unordered_multiset是以key为元素无序的关联容器,搜索、移除和插入操作是平均常数的时间复杂度。unordered_multiset在内部没有按任何顺序排列,而是放在桶当中的,放进哪个桶是通过计算key的hash值来决定的。和unordered_set不同的是&#xff…

【JS】事件绑定方法自带一个形参e“function(e)”,what is e?

在学习js的时候 我跳过了一部分章节的内容,导致现在学习react的时候很多内容都不知所措,因为这些教程都是建立在它认为你js所有内容都掌握的前提下,当然这是我自身的原因。需要反省。 下面是正题: 我们知道js有很多事件&#…

学习 Python operator 模块的 itemgetter

学习 Python operator 模块的 itemgetter 0. 引言1. itemgetter函数说明1-1. 示例代码1-2. 多级排序 0. 引言 operator模块提供了一系列对操作符的函数化接口,例如:加法、乘法、比较操作等。 itemgetter函数是operator模块中的一个功能,它用…

【一】【SQL】表的增删查改(部分)

表之“增”操作 建表的操作 mysql> create table students(-> id int unsigned primary key auto_increment,-> sn int unsigned unique key,-> name varchar(20) not null,-> qq varchar(32) unique key-> ); Query OK, 0 rows affected (0.03 sec)mysql&g…

v-rep--addon--附加组件

附加组件汉化文档 官网 什么是addon 就是一个lua语言文件; 用户通过编写的lua文件来增加coppeliasim的功能。 addon的作用 通过用户编写的lua语言实现添加coppliasim功能。

Day01:Web应用架构搭建站库分离路由访问配置受限DNS解析

目录 常规的Web应用搭建 三种常规网站搭建模式 程序源码 中间件配置 数据库类型 文件访问路径 总结 章节知识点: 应用架构:Web/APP/云应用/三方服务/负载均衡等 安全产品:CDN/WAF/IDS/IPS/蜜罐/防火墙/杀毒等 渗透命令:文件…

Pytorch添加自定义算子之(1)-安装配置Eigen库

一、安装对应的ubuntu环境 推荐使用Docker FROM nvcr.io/nvidia/pytorch:23.01-py3 RUN pip install tensorboardX RUN pip install pyyaml RUN pip install yacs RUN pip install termcolor RUN pip install opencv-python RUN pip install timm0.6.12 WORKDIR /app COPY . …

Python入门必学:print函数--从基础语法到高级用法

Python入门必学:print函数–从基础语法到高级用法 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 👈 希望得到您…

2024 春招市场行情报告:鸿蒙人才遭“爆抢”

前言 2024年可以说是布道鸿蒙开发行业的最佳时机,华为在千帆启航仪式会中发布会中表示,已有200家头部企业加入原生开发当中,并且一直有高薪抢人的局面,这一信息已经引起业界很大关注。 因此有很多公司开始准备要招聘鸿蒙工程师&…

机器学习YOLO操作全流程​​编

YOLO介绍 Ultralytics YOLOv8,是最新的著名实时目标检测和图像分割模型。它基于深度学习和计算机视觉的最新进展,提供了无与伦比的速度和精度性能。由于其精简的设计,适用于各种应用,并且可以轻松适配不同的硬件平台,从边缘设备到云端API。 探索 YOLOv8 文档,这是一个全…

R语言【BIEN】——BIEN_occurrence_genus():从BIEN数据库下载特定属的观察记录。

Package BIEN version 1.2.6 Description BIEN_occurrence_genus() 从BIEN数据库下载特定属的观察记录。 Usage BIEN_occurrence_genus(genus,cultivated FALSE,new.world NULL,all.taxonomy FALSE,native.status FALSE,natives.only TRUE,observation.type FALSE,poli…

【MySQL】探索表结构、数据类型和基本操作

表、记录、字段 数据库的E-R(entity-relationship,实体-关系)模型中有三个主要概念: 实体集 、 属性 、 关系集 。 一个实体集对应于数据库中的一个表,一个实体则对应于数据库表 中的一行,也称为一条记录。…

【Linux基础】Linux自动化构建工具make/makefile

背景 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后…

ubuntu 安装jdk8

在Ubuntu上安装Java Development Kit (JDK) 8,可以通过以下两种方法进行: 方法一:通过PPA源安装Oracle JDK 8(不推荐,因为Oracle已停止对JDK 8的公开更新支持) 由于Oracle自2019年起对JDK 8的公共更新仅限…

2/26作业

1.link_stack.c #include "link_stack.h" //申请栈顶指针 top_p creat_top() { top_p top (top_p)malloc(sizeof(top_t)); if(topNULL) { printf("空间申请不成功\n"); return NULL; } top->len 0; top->…