背景

第一次听说 SPI 是阅读《软件框架设计的艺术》,以后陆续在 Log4Net 和 Quartz.Net中发现了以这种形式组织代码的方式,本位给出为什么要区分 SPI 和 API 的一个思考过程。

从面向接口编程说起

我们在“调用方”和“实现方”之间引入了“接口”,上图没有给出“接口”应该位于哪个“包”中,从纯粹的可能性上考虑,我们有三种选择:

  1. “接口”位于“调用方”所在的“包”中。
  2. “接口”位于“实现方”所在的“包”中。
  3. “接口”位于独立的“包”中。

下面让我们依次分析这三种可能性,如果现实中确实有这种可能性,不如我们就为其起个名字以方便交流。

“接口”位于“调用方”所在的“包”中

我们先想象一个场景,以仓储的接口为例:

我们将“仓储接口”放置于“领域层”这个“包”中,实现放在一个独立的“包”中,我们看DDD大师的实现都是这样子,现在来思考一下为什么这么做。

“领域层”的“领域服务”会依赖“仓储接口”,“仓储接口”也会依赖“聚合根”,这两者都是除了“实现依赖”之外的依赖关系,如果将“接口”放到“仓储实现”中就丧失了面向接口编程的意义(编译也不会通过),如果放到“独立层”中呢?会编译不通过,出现双向依赖了。

对于类似这种情况下接口,我们将其称为“SPI”,全程为:service provider interface,“SPI”的规则如下:

  1. 概念上更依赖调用方。
  2. 组织上位于调用方所在的包中。
  3. 实现位于独立的包中。
  4. 常见的例子是:插件模式的插件。

“接口”位于“实现方”所在的“包”中

我们先想象一个场景,以Unity提供的IUnityContainer接口为例,除了维护这个框架的团队之外,我们没有发现谁实现了这个接口,虽然理论上是可以实现这个接口的(如果能实现的话,我们何不自己弄额Ioc容器呢?)。

对于类似这种情况下的接口,我们将其称作为“API”,“API”的规则如下:

  1. 概念上更接近实现方。
  2. 组织上位于实现方所在的包中。
  3. 实现和接口在一个包中。

“接口”位于独立的“包”中

这里就不说场景了,如果一个“接口”在一个上下文是“API”,在另一个上下文是“SPI”,那么你就可以这么组织。

需要注意的事项

不管是SPI或API,接口都是可以组织到独立的“包”中,这么做是否有意义,自己来做出决定了。

SPI和API也不一定是接口,我这里都是指狭义的具体的接口。

另外一张图

备注

每一次思考都伴随着收获,也离不开和朋友们的交流,天更蓝了。

设计原则:小议 SPI 和 API的更多相关文章

  1. API/SPI可扩展设计原则(转)

    API/SPI可扩展设计原则 博客分类: [设计体系]架构模式 API/SPISPISPI原则JAVA SPISPI机制  写本篇主要是用来后面写一篇可扩展性软件设计打好基础(苦于找不到一篇关于API ...

  2. javascript的api设计原则

    前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博文同时也参考了其他一些文章,相关地址会在后面贴出来.很难做到 ...

  3. GOTO Berlin: Web API设计原则

    在邮件列表和讨论区中有很多与REST和Web API相关的讨论,下面仅是我个人对这些问题的一些见解,并没有绝对的真理,InnoQ的首席顾问Oliver Wolf在GOTO Berlin大会上开始自己的 ...

  4. Atitit. Api 设计 原则 ---归一化

    Atitit. Api 设计 原则 ---归一化 1.1. 叫做归一化1 1.2. 归一化的实例:一切对象都可以序列化/toString  通过接口实现1 1.3. 泛文件概念.2 1.4. 游戏行业 ...

  5. Atitit.论图片类型 垃圾文件的识别与清理  流程与设计原则 与api概要设计 v2 pbj

    Atitit.论图片类型 垃圾文件的识别与清理  流程与设计原则 与api概要设计 v2 pbj 1. 俩个问题::识别垃圾文件与清理策略1 2. 如何识别垃圾图片1 2.1. 体积过小文件<1 ...

  6. 优秀的API接口设计原则及方法(转)

    一旦API发生变化,就可能对相关的调用者带来巨大的代价,用户需要排查所有调用的代码,需要调整所有与之相关的部分,这些工作对他们来说都是额外的.如果辛辛苦苦完成这些以后,还发现了相关的bug,那对用户的 ...

  7. 好RESTful API的设计原则

    说在前面,这篇文章是无意中发现的,因为感觉写的很好,所以翻译了一下.由于英文水平有限,难免有出错的地方,请看官理解一下.翻译和校正文章花了我大约2周的业余时间,如有人愿意转载请注明出处,谢谢^_^ P ...

  8. RESTful API的设计原则

    好RESTful API的设计原则   说在前面,这篇文章是无意中发现的,因为感觉写的很好,所以翻译了一下.由于英文水平有限,难免有出错的地方,请看官理解一下.翻译和校正文章花了我大约2周的业余时间, ...

  9. 好的RESTful API的设计原则

    转载自一位大佬 英文原版 Principles of good RESTful API Design Good API design is hard! An API represents a cont ...

随机推荐

  1. 用socket发送匿名邮件之python实现

    发送邮件可以用smtp协议,整个过程为: 用户代理(user-agent,比如outlook.foxmail等邮件客户端)---(smtp协议)--->本地邮件服务器 --- (smtp协议)- ...

  2. Web前端开发最佳实践(5):正确闭合HTML标签,停止使用不标准的标签和属性

    正确闭合HTML标签 HTML元素的内容模型定义了元素的结构,表明元素可以包含哪些内容以及元素可以有哪些属性.元素可以包含的内容包括其他元素和字符,但是也有一些元素是空元素,即不能包含任何内容,这些元 ...

  3. Codeforces Round #496 (Div. 3) F - Berland and the Shortest Paths

    F - Berland and the Shortest Paths 思路:还是很好想的,处理出来最短路径图,然后搜k个就好啦. #include<bits/stdc++.h> #defi ...

  4. HDU 6024 Building Shops

    $dp$. $dp[i]$表示到$i$位置,且$i$位置建立了的最小花费,那么$dp[i] = min(dp[k]+cost[i+1][k-1])$,$k$是上一个建的位置.最后枚举$dp[i]$,加 ...

  5. Markdown 实现首行缩进

    把输入法由半角改为全角. 两次空格之后就能够有两个汉字的缩进. 在开头的时候,先输入这个,然后紧跟着输入文本即可.分号也不要掉.        

  6. docker chown: changing ownership of '/var/lib/XXX': Permission denied

    Links: 1.entos7下docker Permission denied 2.查看 SELinux状态及关闭SELinux 方法: 1.查看SELinux状态sestatus -vgetenf ...

  7. Bzoj2120/洛谷P1903 数颜色(莫队)

    题面 Bzoj 洛谷 题解 考虑对操作离线后分块处理询问操作(莫队算法),将询问操作按照编号分块后左端点第一关键字,右端点第二关键字排序(分块大小为\(n^{\frac 23}\)),对于每一个询问操 ...

  8. 虚拟环境中pip install requirments.txt: Cannot fetch index base URL https://pypi.python.org/simple/

    Stackoverflow  : http://stackoverflow.com/questions/15501133/python-pip-error-cannot-fetch-index-bas ...

  9. python统计文本中每个单词出现的次数

    .python统计文本中每个单词出现的次数: #coding=utf-8 __author__ = 'zcg' import collections import os with open('abc. ...

  10. MySQL笔记(五)之表的连接

    MySql数据库中表的连接一共有如下几种 INNER JOIN 内连接 语法: SELECT column_name(s) FROM table_name1 INNER JOIN table_name ...