接口隔离原则

定义

接口隔离原则(Interface Segregation Principle, ISP),定义为:

  1. Clients should not be forced to depend upon interfaces that they don’t use. (客户端不应该依赖它不需要的接口。)
  2. The dependency of one class to another one should depend on the smallest possible interface. (类间的依赖关系应该建立在最小的接口上。)

接口隔离原则是对接口的使用进行约束规范的一个原则,它告诉我们要想把接口用好,关键在于隔离。隔离,指断绝接触、断绝往来。那么我们使用接口时,要隔离什么东西呢?对于上述定义的第1点,“客户端不应该依赖它不需要的接口”,这里的隔离是指客户端和它不需要的接口隔离,也就是客户端不要使用它不需要的接口,这个很容易理解,在实践中也很容易实现。我们着重看一下第2点,“类间的依赖关系应该建立在最小的接口上”,它要求“最小的接口”,也就是该接口中没有多余的方法,所以这里的隔离是指和多余的方法隔离。

综上所述,接口隔离原则告诉我们,不要把一大堆方法塞进一个接口里,导致这个接口变得臃肿无比。应该要根据实际需要,让接口中只有用得上的方法,也就是说要细化我们的接口

好处

现在我们知道,接口隔离原则的要点,就是要细化我们的接口。那么这样做具体有什么好处呢?主要有四个好处,分别是:1.避免接口污染;2.提高灵活性;3.提供定制服务;4.实现高内聚。下面就来详细说一下接口隔离原则的好处。

避免接口污染

一个类如果要实现一个接口,那么就要实现这个接口要求的所有方法,如果这个接口里面包含这个类不需要的方法,那么就会造成接口污染,这是不好的设计,会对系统留下隐患。

比如说我们有一个枪的接口,枪有两个属性:扳机和子弹。枪有一个功能:射杀。其接口如下:


 

@protocol IGun <NSObject>
@property (strong,nonatomic) id trigger;//扳机
@property (strong,nonatomic) id bullet;//子弹
- (void)shot;//射杀
@end

然后我们现在需要一个玩具枪的类。玩具枪有扳机也有子弹,只是不能射杀。为了图方便,我们直接用IGun这个接口来实现我们的玩具枪:

#import "IGun.h"
@interface ToyGun : NSObject<IGun>
@end@implementation ToyGun
@synthesize trigger = _trigger,bullet = _bullet;
- (void)shot{//空实现,什么也不做
}
@end

玩具枪是不能射杀的,但是由于它实现了IGun这个接口,所以只能空实现它并不需要的shot方法,于是玩具枪这个类就被污染了。这好像也没有什么不妥,但是这是有隐患的,因为玩具枪一旦实现了IGun接口,那么在程序里它就代表一把能射杀的枪。假设在后面突然遇到了一个老虎,唯一保命的方法就是拿枪射杀这个老虎,结果你拿到的是你之前为了图方便做的ToyGun,那么你面临的就是灭顶之灾。

提高灵活性

一个类是可以同时实现多个接口的,所以将一个臃肿的接口分割为若干个小接口,通过小接口的不同组合可以满足更多的需求。

举个例子。我们现在需要一个代表美女的接口,美女的标准也很明确:面貌、身材和气质,那么我们的美女接口就出来了:

@protocol IPrettyGirl <NSObject>
- (void)goodLooking;//好面貌
- (void)niceFigure;//好身材
- (void)greatTemperament;//好气质
@end

这并没有什么问题。但是在现实中,一定是要美貌和气质兼备的才算美女吗?非也,其实也有长得不好看,但是气质很好的气质美女的,当然也有没有气质但是长得好看的美女。这样上面的接口就不适用了,因为按照上面的的接口,只有长得好看而且气质好的才算美女。

可以通过细化这个接口解决这个问题。上述的接口可以一分为二:

只有外貌好的美女:


 

@protocol IGoodBodyGirl <NSObject>
- (void)goodLooking;//好面貌
- (void)niceFigure;//好身材
@end

只有气质好的美女:

@protocol IGreatTemperamentGirl <NSObject>
- (void)greatTemperament;//好气质
@end

然后通过这两个接口的不同组合,就能满足外貌美女、气质美女和外貌气质俱佳的美女的不同需求了。所以,细化接口可以让我们的接口更加灵活,满足更多需求。

提供定制服务

什么是定制服务?定制服务就是单独为一个个体提供优良的服务。我们在做系统设计时也需要考虑对系统之间或模块之间的接口提供定制服务。提供定制服务就必然有一个需求:只提供访问者需要的方法。这也是可以通过细化接口实现的。

比如我们开发了一个图书管理系统,其中有一个查询图书的接口:

@protocol IBookSearcher <NSObject>
- (void)searchByAuthor;//根据作者搜索
- (void)searchByTitle;//根据书名搜索
- (void)searchByCatagory;//根据分类搜索
- (void)complexSearch;//复杂的搜索
@end

我们的图书馆管理系统的访问者有管理人员和公网,其中complexSearch方法非常损耗服务器的性能,它只提供给管理人员使用。其他方法管理人员和公网都可以使用。公网这部分是另一个项目组在开发的,所以当时我们口头上跟公网项目组说明不能在公网上调用complexSearch这个方法。图书馆管理系统上线后,有一天发现系统速度非常慢,在熬了一个通宵排查后,发现是由于公网项目组某个程序员的疏忽,把complexSearch方法公布到了公网中...

显然通过口头的方式说哪一个方法不能调用是不管用的,要想彻底解决这个问题,还是得通过细化接口,为访问者定制专有的接口才行。那么上述的接口可以一分为二:

简单的搜索:

@protocol ISimpleBookSearcher <NSObject>
- (void)searchByAuthor;//根据作者搜索
- (void)searchByTitle;//根据书名搜索
- (void)searchByCatagory;//根据分类搜索
@end

复杂的搜索:

@protocol IComplexBookSearcher <NSObject>
- (void)complexSearch;//复杂的搜索
@end

这样我们就可以分别给管理人员和公网定制接口了:

  1. 给管理人员提供ISimpleBookSearcherIComplexBookSearcher两个接口;
  2. 给外网提供ISimpleBookSearcher这个接口。

所谓的定制服务,就是通过细化接口,实现给不同的客户提供不同的接口的目的。定制服务可以有效避免因为给客户提供了多余的方法而造成的风险。

高内聚

什么是高内聚?高内聚就是提高接口、类、模块的处理能力,减少对外的交互。比如说,你告诉你的下属“一个小时之内去月球搬一块石头回来”,然后你就躺在海滩上晒着太阳喝着果汁,一个小时之后你的下属就搬着一块月亮上的石头回来给你了。这种不讲任何条件,不需要你关心任何细节,立即完成任务的行为就是高内聚的表现。

具体到接口中,还是尽量细化你的接口。接口是对外界的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本。

注意

接口隔离原则和单一职责原则非常类似。单一职责原则要求接口的职责是单一的,而接口隔离原则要求接口尽量细化,它们有异曲同工之妙,都是要让我们的接口功能尽量单一,尽量小。

但是,单一职责原则的着重点是在“职责”,而接口隔离原则只单纯地要求接口最小化。那么,如果已经满足单一职责原则的接口,在当前的需求下还可以继续细化,那么还需要细化吗?答案是不要再细化了。在实践中,接口设计的粒度越小,系统就越灵活,这是事实。但是灵活的同时也带来了系统的复杂化,导致开发难度增加。所以接口并不是越小越好,必须要有一个度。当单一职责原则和接口隔离原则存在矛盾时,以满足单一职责原则为底线。


 

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

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

相关文章

Asp.net TextBox常规输入验证

Asp.net TextBox只能输入数字<asp:textbox id"TextBox1" οnkeyup"if(isNaN(value))execCommand(undo)" runat"server" Width"80px" onafterpaste"if(isNaN(value))execCommand(undo)"></asp:textbox> 其实服务…

依赖倒置原则

定义 依赖倒置&#xff1f;大家可能会觉得高深莫测。但是相信听我一翻解说之后&#xff0c;你就会恍然大悟&#xff0c;甚至你早已掌握到它的精髓了。我们先看一下依赖倒置原则的定义&#xff1a; High level modules should not depend upon low level modules. Both should …

求一个连通图的割点(去掉一个点后图不再连通)

题目&#xff1a;求一个连通图的割点&#xff0c;割点的定义是&#xff0c;如果除去此节点和与其相关的边&#xff0c;图不再连通&#xff0c;描述算法。 分析&#xff1a; 1. 最简单也是最直接的算法是&#xff0c;删除一个点然后判断连通性&#xff0c;如果删除此点&#xff…

深入浅出 Java Concurrency (6): 锁机制 part 1[转]

前面的章节主要谈谈原子操作&#xff0c;至于与原子操作一些相关的问题或者说陷阱就放到最后的总结篇来整体说明。从这一章开始花少量的篇幅谈谈锁机制。 上一个章节中谈到了锁机制&#xff0c;并且针对于原子操作谈了一些相关的概念和设计思想。接下来的文章中&#xff0c;尽可…

行为树

行为树(Behavior Tree)&#xff0c;有4大类型的Node&#xff1a; (1) Composites Node 组合节点&#xff0c;包括经典的&#xff1a;Sequence&#xff0c;Selector&#xff0c;Parallel * Selector Node 当执行本类型Node时&#xff0c;它将从begin到end迭代执行自己的Ch…

SCRUM 12.03

第二轮迭代从今天起正式开始了。12月3日&#xff0c;我们举行了一次组会。 第一轮迭代结束时&#xff0c;我们意识到第二轮迭代需要实现的功能主要如下&#xff1a; 在下次迭代的时候实现对多个网站的信息进行比较取最优惠的选择&#xff0c;目前我们劲针对了一个网站的信息进行…

阻止页面双击选中文本

轮播图实现中&#xff0c;发现当点击切换按钮时&#xff0c;如果用户点快乐&#xff0c;双击了按钮&#xff0c;就会选中文本。十分影响浏览效果&#xff0c;所以有了这篇文章。 IE以及谷歌下的解决办法&#xff1a; <div id"zell-carousel" class"zell-caro…

STL内嵌数据类型: value_type

使用stl库的时候一直对value_type这个东西理解的不是很好&#xff0c;可以说就是不理解。今天看了《STL源码剖析》才恍然大悟。这里稍作记录。 每个STL中的类都有value_type这种东西&#xff0c;通俗的说value_type 就是stl容器盛装的数据的数据类型&#xff0c;例如&#xff…

Boost.Python实现Python C/C++混合编程

导出函数 #include<string> #include<boost/python.hpp>using namespace std; using namespace boost::python;char const * greet() {return "hello,world";}BOOST_PYTHON_MODULE(hello_ext) {def("greet", greet); } import hello_ext pri…

swift UIActivityIndicatorView

// // ActivityIndicatorViewController.swift // UIControlDemo // // Created by on 14/12/1. // Copyright (c) 2014年 马大哈. All rights reserved. // import UIKit class ActivityIndicatorViewController: BaseViewController { var waitActivity:UIActivityIndi…

UE4打包后如何调试

在项目打包后发现有一个数组越界问题&#xff0c;然而无论是 Play in Editor或是 VS选为DebugGame后启动&#xff0c;游戏都没有任何问题&#xff0c;越界问题只在打包后出现。这里记录一下自己的Debug方法。 首先将项目以DebugGame配置打包&#xff1a; 更改打包配置&#xff…

asp.net 使用my97 datepicker实现前后两个日期的范围界定

说明&#xff1a;日期选择后&#xff0c;前面的日期小于等后面的日期&#xff0c;后面的日期大于等于前面的日期。点点看就知道了:) &#xff5e; 这里将周末日期不可选。代码如下&#xff1a; 1 <html xmlns"http://www.w3.org/1999/xhtml">2 <head runat…

james-2.3.2中的配置

james&#xff1a;1、解压缩2、先运行一遍3、修改配置 apps\james\SAR-INF\config.xml(1)postmaster(2)servername localhost --> abclocalhost j08.com --> abcj08.com 自动检查名称和IP设为false(3)注释掉RemoteAddrNotInNetwork(4)添加虚拟域名&#xff0c;指向localh…

Win7下安装配置gVim

本文根据vim官网的《Simple Steps to Help You Install gVim on Windows 7》【1】一文整理而成。 1. 下载gVim 在http://www.vim.org/download.php/pc 下找到“PC: MS-DOS and MS-Windows”&#xff0c;下载“gvim74.exe”【2】。 2. 安装gVim 1. 安装时可以选择更改目录&#…

ActiveReports 报表控件官方中文入门教程 (2)-创建、数据源、浏览以及发布

ActiveReports 报表控件官方中文入门教程 (2)-创建、数据源、浏览以及发布 原文:ActiveReports 报表控件官方中文入门教程 (2)-创建、数据源、浏览以及发布本篇文章将阐述首次使用 ActiveReports 报表控件 的方法&#xff0c;包括添加报表文件、绑定数据源以及如何发布报表等内…

C++ Lambda表达式基本用法

创建一个匿名函数并执行。采用的是配对的方括号[]。实例如下&#xff1a; 1 2 3 4 5 6 7 8 9 #include <iostream> using namespace std; int main() { []{ cout << "Hello,Worldn"; }(); } 我们也可以方便的将这个创建的匿名函数赋…

每日一测4(装箱与拆箱)

1、定义 装箱&#xff1a;用于在垃圾回收堆中存储值类型。装箱是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。 拆箱&#xff1a;从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。 2、为什么要装箱&#xff1a; &#xff08;1&#x…

flex 正则表达式匹配规则

正则表达式扫描的优先级 1. 先根据空格&#xff0c;tab&#xff0c;回车分割字符串&#xff0c;作为正则表达式匹配的基础 2. 找到完全匹配的正则表达式&#xff0c;以排列在前面的优先级为高 3. 如果找不到匹配的表达式&#xff0c;那么从头开始截取字符串来查找合…

笔记本多硬盘win7下U盘安装Cnetos7引导问题!

CentOS7出来的时间已经不算短了&#xff0c;前段时间一直在虚拟机上使用&#xff0c;最近闲下来了&#xff0c;就像在自己的笔记本上装一个win7和Centos7的双系统体验以下实体机的效果&#xff0c;几经波折之后终于顺利的装上了WIN7和CentOS7的双系统&#xff01;在这里主要是想…