10 面向接口编程(上):一切皆服务,服务基于协议

news2025/1/9 17:06:53

按照面向接口编程的理念,将每个模块看成是一个服务,服务的具体实现我们其实并不关心,我们关心的是服务提供的能力,即接口协议。那么框架主体真正要做的事情是什么呢?其实是:定义好每个模块服务的接口协议,规范服务与服务之间的调用,并且管理每个服务的具体实现

所有的服务都去框架主体中注册自身的模块接口协议,其他的服务调用功能模块的时候,并不是直接去这个服务获取实例,而是从框架主体中获取有这个接口协议的服务实例。

这样,所有的模块服务都不和具体的服务进行交互,而是和框架主体进行交互,所有的接口也都注册在框架主体中,非常方便管理。

在这里插入图片描述
每个模块服务都做两件事情:一是它和自己提供的接口协议做绑定,这样当其他人要使用这个接口协议时能找到自己;二是它使用到其他接口协议的时候,去框架主体中寻找。

所以,这个时候,每个模块服务都是一个“服务提供者”(service provider),而我们主体框架需要承担起来的角色叫做“服务容器”(service container),服务容器中绑定了多个接口协议,每个接口协议都由一个服务提供者提供服务。

在框架初始化启动的时候,我们可以选择在服务容器中绑定多个服务提供者,每个服务提供者对应一个凭证。当要使用到某个服务的时候,再根据这个凭证去服务容器中,获取这个服务提供者提供的服务。这样就能很方便地获取服务了。

这两个结构的逻辑非常重要,这里我再强调一下。我们的设计是将每个服务,不管是配置、还是日志、还是缓存,都看成是一个服务。

这个服务,通过提供一个服务提供者注册到服务容器中。服务提供者提供的是“创建服务实例的方法”,服务容器提供的是“实例化服务的方法”。至于这个服务实例拥有哪些能力,即符合哪个接口协议,是预先在框架主体中定义好的。

服务器提供者接口定义

个服务提供者需要有哪些能力呢?一共有五个能力:

  • 获取到服务凭证的能力Name
  • 创建服务实例化方法的能力Register
  • 获取服务实例化方法参数的能力Params
  • 两个与实例化控制相关的方法:控制实例化时机IsDefer、实例化预处理Boot

将此接口放在framework/provider.go中。

基本定义

每个服务提供者有一个凭证,用来和容器做绑定,则它有一个获取自身凭证的方法Name:

// Name 代表了这个服务提供者的凭证
Name() string

然后它有一个创建服务实例的方法,在绑定后,如果容易要初始化一个服务提供者实例,就会调用创建实例的方法。

按照面向接口编程的思想,每个具体服务“创建服务实例”的方法不一样,比如日志服务初始化的时候可能需要有日志输出地址,但是配置服务初始化的时候需要有配置文件地址,但是我们这里需要规范它们的输入和输出,使用 Golang 中的 function type,也叫函数定义,是可以做这个事情的。

// NewInstance 定义了如何创建一个新实例,所有服务容器的创建服务
type NewInstance func(...interface{}) (interface{}, error)

这个 NewInstance 就是一个函数定义,它规定所有创建服务实例的方法必须:有相同的参数 interface{} 数组,并且返回 interface{}和错误信息这两个数据结构。

  • interface{} 数组代表实例化一个服务所需要的参数,我们这里设计为可变参数,为的是适配不同数量、不同类型的参数需求;
  • 返回值返回的 interface{} 结构代表了具体的服务实例。

定义好了“创建服务实例的方法”的函数,我们再看服务提供者的创建能力如何实现,也就是 NewInstance 方法,它的返回值就是刚才写的 NewInstance 的函数定义。


// Register 在服务容器中注册了一个实例化服务的方法,是否在注册的时候就实例化这个服务,需要参考 IsDefer 接口。
Register(Container) NewInstance

而对于方法的输入参数,将服务容器传进来是因为,如果后续希望根据一个服务的某个能力,比如配置服务的获取某个配置的能力,返回定义好的不同 NewInstance 函数,那我们就需要先从服务容器中获取配置服务,才能判断返回哪个 NewInstance。

“创建服务实例的方法”的能力,除了实现 NewInstance 方法之外,还需要注册 NewInstance 方法的参数,即可变的 interface{}参数。所以我们的服务提供者还需要提供一个获取服务参数的能力。

// Params params 定义传递给 NewInstance 的参数,可以自定义多个,建议将 container 作为第一个参数Params(Container) []interface{}
Param(Container) []interface{}

实例化过程的控制

到这里服务提供者的能力已经基本设计好了。不过我们可以再思考下实例化的过程,看看还有没有什么讲究。

  • 实例化的时机,可以在服务提供者注册的时候,也可以是第一次获取服务的时候,即是注册的时候就实例化,还是延迟到获取服务的时候实例化。

所以我们需要有一个能力能控制实例化的时机,对应到服务提供者上,要提供告知服务容器是否延迟实例化的方法 IsDefer。同样在 framework/provider.go 中。

// IsDefer 决定是否在注册的时候实例化这个服务,如果不是注册的时候实例化,那就是在第一次 make 的时候进行实例化操作
// false 表示不需要延迟实例化,在注册的时候就实例化。true 表示延迟实例化
IsDefer() bool
  • 实例化之前有可能需要做一些准备工作,比如在每次实例化之前,想记录一下日志,或者想通过确认某些配置,修改一下实例化参数。

所以这里我们需要设计一个在实例化前调用准备工作的函数 Boot。它的参数是服务容器,返回值是一个 error,在实例化服务的时候,如果准备工作 Boot 失败了,那么我们就不进行后续的实例化操作了,将这个 error 直接返回给获取服务的方法。

// Boot 在调用实例化服务的时候会调用,可以把一些准备工作:基础配置,初始化参数的操作放在这个里面。
// 如果 Boot 返回 error,整个服务实例化就会实例化失败,返回错误
Boot(Container) error

这样, framework/provider.go 中完整代码如下:

package framework

// NewInstance 定义了如何创建一个新实例,所有服务容器的创建服务
type NewInstance func(...interface{}) (interface{}, error){}

// ServiceProvider 定义一个服务提供者需要实现的接口
type ServiceProvider interface {
  // Register 在服务容器中注册了一个实例化服务的方法,是否在注册的时候就实例化这个服务,需要参考 IsDefer 接口。
  Register(Container) NewInstance
  // Boot 在调用实例化服务的时候会调用,可以把一些准备工作:基础配置,初始化参数的操作放在这个里面。
  // 如果 Boot 返回 error,整个服务实例化就会实例化失败,返回错误
  Boot(Container) error
  // IsDefer 决定是否在注册的时候实例化这个服务,如果不是注册的时候实例化,那就是在第一次 make 的时候进行实例化操作
  // false 表示不需要延迟实例化,在注册的时候就实例化。true 表示延迟实例化
  IsDefer() bool
  // Params params 定义传递给 NewInstance 的参数,可以自定义多个,建议将 container 作为第一个参数
  Params(Container) []interface{}
  // Name 代表了这个服务提供者的凭证
  Name() string
}

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

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

相关文章

That引导的宾语从句

That引导的宾语从句指的是that为宾语从句的引导词。宾语从句:置于动词、介词等词性后面,在句子中起宾语作用的从句叫做宾语从句。宾语从句分为三类:动词的宾语从句,介词的宾语从句和形容词的宾语从句。 一、that引导的宾语从句(在…

《数据万象带你玩转视图场景》第一期:avif图片压缩详解

前言随着硬件的发展,不管是手机还是专业摄像设备拍出的图片随便可能就有几M,甚至几十M,并且现在我们处于随处可及的信息海洋里,海量的图片带来了存储问题、带宽问题、加载时延问题等等。对图片信息进行有效的压缩处理无疑会极大的…

ARM架构Ubuntu下使用Docker安装MySQL

大家好,我是中国码农摘星人。 欢迎分享/收藏/赞/在看! 由于ARM架构的限制,许多软件还没有做到完全适配,CentOS、MySQL等软件安装频繁出错。于是决定做一栏相关软件环境安装的文章。 基础信息 Apple M1 ProUbuntu 22.04 运行 使…

Python 如何安装 MySQLdb ?

人生苦短 我用python Python 标准数据库接口为 Python DB-API, Python DB-API为开发人员提供了数据库应用编程接口。 Python 数据库接口支持非常多的数据库, 你可以选择适合你项目的数据库: GadFlymSQLMySQLPostgreSQLMicrosoft SQL Serve…

来 CSDN 三年,我写了一本Python书

大家好,我是朱小五。转眼间已经来 CSDN 3年了,其中给大家一共分享了252篇Python文章。 但这三年,最大的收获还是写了一本Python书! 在这个自动化时代,我们有很多重复无聊的工作要做。想想这些你不再需要一次又一次地做…

站内信箱系统的设计与实现

技术:Java、JSP等摘要:在经济全球化和信息技术成为发展迅速的今时今日,人们通过电子邮件收发进行信息传递已经成为主流。随着互联网和网络办公的发展,电子邮件正在被广泛应用在人们的日常生活中。跟据调查研究统计,在全…

文件系统-

文件系统 是一个面向用户的可视化管理类型的操作系统 其实就是管理硬盘的基本单位扇区,然后将存储数据可视化管理给用户 文件系统包含两个部分 文件的集合和目录结构 对于用户和系统来说文件系统时不一样的 操作系统只解释可执行文件 文件内部结构 文件就是基本…

【JVM】详解Java内存区域和分配

这里写目录标题一、前言二、运行时数据分区2.1程序计数器(PC)2.2 Java虚拟机栈2.3 本地方法栈2.4 Java堆2.5 方法区2.5.1 运行时常量池2.6 直接内存三、HotSpot虚拟机对象探秘3.1 对象的创建3.2 对象的内存布局3.3 对象的访问定位一、前言 C/C需要自行回收和释放已经没用的对象…

2023年 Java 发展趋势

GitHub 语言统计表明,Java在编程语言中排名第二,而在2022年的TIOBE指数中,Java排在第四。 抛开排名,Java是自诞生以来企业使用率最高的编程语言,作为一种编程语言,它比许多竞争对手都有更多的优点&#xf…

【C/C++】逗号表达式、算术运算符优先级

一、逗号表达式 1、如下图中代码,为变量d赋值,d的值为逗号表达式中的哪一个呢? 运行结果:d的值为6 2、再举个例子 运行结果:d的结果还是6 3、再举个例子 运行结果 以上面三种不同的逗号表达式为例,…

IronOCR 2023.3.2 Crack by Xacker

适用于 .NET 2023.3.2 的 IronOCR 提高了从 PDF 阅读文本时的可靠性。2023 年 3 月 2 日 - 10:22 新版本特征 添加了与 Amazon AWS (Amazon Linux) 的兼容性。添加了对各种旧版 Linux 发行版的兼容性。提高了从 PDF 阅读文本时的可靠性。创建可搜索的 PDF 时提高了速度和保真度…

JVM调优面试题——基础知识

文章目录1、JDK,JRE以及JVM的关系2、编译器到底干了什么事?3、类加载机制是什么?3.1、装载(Load)3.2、链接(Link)3.3、初始化(Initialize)4、类加载器有哪些?5、什么是双亲委派机制?6、介绍一下JVM内存划分&#xff08…

[蓝桥杯] 数学与简单DP问题

文章目录 一、简单数学问题习题练习 1、1 买不到的数目 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 饮料换购 1、2、1 题目描述 1、2、2 题解关键思路与解答 二、DP问题习题练习 2、1 背包问题 2、1、1 题目描述 2、1、2 题解关键思路与解答 2、2 摘花生 2、2、1 题目…

收个滴滴Offer:从小伙三面经历,看看需要学点啥?

说在前面 在尼恩的(50)读者社群中,经常有小伙伴,需要面试大厂。 后续结合一些大厂的面试真题,给大家梳理一下学习路径,看看大家需要学点啥? 这里也一并把题目以及参考答案,收入咱…

Spring 容器创建初始化,获取bean流程分析

Spring 容器创建初始化,获取bean流程分析 Spring 容器创建初始化 流程分析 1、首先读取bean.xml 文件 2、扫描指定的包 com.hspedu.spring.component 2.1、扫描包,得到bean的class对象,排除包下不是bean的 2.2、扫描将bean信息封装BeanDef…

python之selenium库安装及用法(定位法、获取文本、文本框输入、鼠标点击、滑动滚动条)

一、selenium库安装 pip install selenium二、浏览器驱动安装 谷歌浏览器驱动下载地址:https://chromedriver.storage.googleapis.com/index.html 根据你电脑的谷歌浏览器版本,下载相应的就行。我下载的是110.0.5481.XX中的chromedriver_win32.zip 下载…

无公网IP快解析实现U+随时随地访问

现阶段商品从生产到消费者手中要经过多个环节,为实现对每一个环节进行管理,越来越多的企业选择通过信息化手段来实现。供应链管理系统配合供应链中各实体的业务需求,使操作流程和信息系统紧密配合,做到各环节无缝链接,…

【C++】string类的使用

目录 一、标准库中的string类 二、string类的常用接口 1、string类对象的常见构造 2、string类对象的容量操作 2.1、size 与 length 2.2、capacity 与 reserve 2.3、resize 2.4、总结 3、string类对象的访问及遍历操作 3.1、operator[] 与 at 3.2、begin end 3.3、…

Portraiture5人像磨皮润色修饰插件

Portraiture3和Portraiture4这两个版本大家用的比较多,那是因为这两个版本是中文比较全的版本。portraiture是一款强大的64位PS磨皮滤镜,利用该PS滤镜插件可以对图片中的人物进行润色,磨皮等操作,处理皮肤材质、头发等。帮您消除了…

HNU工训中心:平台 2HDL 语言与验证实验报告

一、自定 FSM 说明 1、状态描述 State0:睡觉,如果闹钟响则起床吃早餐,否则继续睡觉 State1:吃早餐,吃完去上课 State2:上课,上完课后如果要开会就去开会,否则去自习 State3&…