【译】Understanding SOLID Principles - Interface Segregation Principle

Understanding SOLID Principles: Interface Segregation Principle

这是理解SOLID原则,关于接口隔离原则如何帮助我们创建简单的抽象接口,并使客户端代与接口之间存在的更少的依赖关系。

接口隔离原则是什么

Clients should not be forced to depend on methods that they do not use.

客户端代码不应当被迫依赖于它们不需要的方法。

这个原则本身与单一职责原则关系十分紧密,它意味着当你在定义你的抽象层代码时,不应当在客户端代码在实现抽象逻辑时,暴露一些客户端代码不需要使用或者关心的方法。

进一步说明的话,就是当你有意地在抽象层中暴露的方法时,这意味着所有实现这些抽象逻辑的客户端代码都必须要实现所有的抽象方法,尽管这些方法并不一定都对客户端代码有意义。

将你的接口的保持精简和小颗粒度,并且不要在它们中间增加无用的抽象方法,当你在对新的抽象接口进行命名时,你就会拥有更好的选择,因为你已有了若干小颗粒的命名类型。这样做的意义在于当你在需要提供一个更加大颗粒度的抽象接口时,你可以拥有足够的灵活性来将已有的小颗粒度接口进行组合。

如何实践接口隔离原则

这个例子是关于一个ATM用户界面的抽象接口,这个接口会处理诸如存款请求、取款请求等逻辑,从这个例子中我们会了解到,我们如何对这个接口进行隔离,使其进一步划分为多个独立的、更加具体的若干接口。

首先我们应当有一个工具函数库接口,这个接口会描述我们想要暴露的关于byte操作逻辑的方法,让我们创建这样一个接口,如下

type ByteUtils interface {
    Read(b []byte) (n int, err error) // Read into buffer
    Write(b []byte)(n int, err error) // Write into buffer
    Trim(b []byte, exclusions string)[]byte // Trim buffer by removing bytes from the exclusion chars
}

它可以正常工作一段时间,但是很快我们就会发现以下两个问题:

  • 它的命名ByteUtils太过于通用,如果我们仅通过命名本身,基本无法获取任何具体的信息
  • 当使用它时,会有一些古怪的感觉,因为当你根据不同的优化场景来按不同逻辑实现trim方法时,你所实现的readwrite几乎没什么差别,但是你却需要重复地实现它们,同时在某些不需要读或者写的场景,仍然需要实现它们。

所以它虽然能够正常工作,但是却不够好。

我们可以通过创建三个更精简、更具体的接口来替代原先通用的接口:

type Reader interface {
    Read(b []byte) (n int, err error) 
}
type Writer interface {
    Write(b []byte)(n int, err error) 
}
type Trimmer interface {
    Trim(b []byte, exclusions string)[]byte 
}

这种颗粒度比较细的接口也可以称为角色接口,因为它们更易于重构和改变,甚至对于已经定义好的角色和目的也可以很容易的进行重新部署和定义。

在这三个基础上,我们可以通过组合它们来获取一个更有关联性的接口列表,比如:

type ReadWriter interface {
    Reader
    Writer 
}
type TrimReader interface {
    Trimmer
    Reader
}

这意味客户端代码拥有了可以根据它们各自的需求来组合抽象层接口的灵活性,这样就会避免在实现抽象接口时不必要的麻烦(比如必须要实现某些无用的方法),比如上面的TrimReader的实现并未包含多余的Write方法的声明。

总结

正如你所看到的,通用的接口往往会无意识的将自己和类的实现耦合在了一起,所以你应当尽量的避免这种情况的发生。在设计接口时,你应当时刻提醒自己,我是否需要使用所有在接口中声明的方法呢?如果不是的话,将接口细分为更多个更精简、更具体的接口。

正如甘地曾经说过:

你的行动决定你的习惯,你的习惯决定你的价值,你的价值会决定你的命运。

如果在架构中,你每次都会经过仔细思考,会按照好的模式来进行设计,它将会成为一种习惯,自然慢慢会转变为你的价值或者原则,最终则会成为你的命运,比如成为了一个始终给予完善解决方案的软件架构师。

我的观点是,始终通过挑战自己来变的更好,在某些时刻,你可能会遇到问题,但是往往你可能已经拥有了答案。

Happy coding!

译者注

对于接口隔离原则的理解,我一直觉的它本身其实是单一职责原则的一个扩展,但是它们之间也有细微的不同:

  • 单一职责原则往往面向实现层,比如具体的类或者某个方法
  • 接口隔离原则往往面向抽象层,比如一些抽象类或者抽象方法

所以将两个原则结合起来看的话,可以很容器得到当时提出这两个原则的人的意图,那就是一定要时刻保持简单

在实际工作中,我深知保持简单是一件十分困难的事情,因为工程师本身的使命便是解决问题,而问题往往充满了未知性,而未知性往往代表着改变,这还没有考虑到在项目实施过程中,产品经理天马行空的设计思路,客户们五花八门的需求等等。在这些外界条件下,我们的代码往往会变得复杂无比,充满了各种反模式和冗余代码,最终会使自己陷入无尽的bug修复和维护工作中,怎么还会有时间进行自我提升呢?

所以,为了能够按时下班,为了能够及早回家,为了能够让我们的拥有更多的时间来提升自己和陪伴家人,在软件设计之初,尽可能地针对将来所面临的改变,在设计层面降低软件抽象模块间的耦合程度,在项目实施时,提高每个具体实现模块内部的内聚程度,同时使它们保持简单,这样便是一个好的开始。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏企鹅号快讯

月薪数万的攻城狮带你了解到什么是C语言编程思想,原来这就是编程思想

什么是编程思想?答案可能很会复杂,但也可以很简单; 一句话来讲就是,用计算机来解决人们实际问题的思维方式,即编程思想; 编程就是为了解决实际中的问题,在思考如何...

2469
来自专栏司想君

前端也要学系列:设计模式之策略模式

上边这句话,从字面来看很简单。但是如何在开发过程中去应用,仅凭一个定义依然是一头雾水。以笔者曾经做过的商户进销存系统为例:

652
来自专栏撸码那些事

【抽象那些事】缺失抽象

1373
来自专栏编程

大数据学习,为什么要先学Java?

计算机编程语言有很多,目前用的多的就是Java,C++,Python,PHP等等。目前大多数学习大数据的人都是选择学习Java,那Java到底好在哪呢?为什么学...

3328
来自专栏web前端教室

怎么能学透一个知识点

其实我个人觉得新手不太应该追求彻底的学透每一个知识点。因为初学的时候,钻的太深并不太利于对JS有一个整体的理解。反而有可能钻牛角尖。但这种方法和心态却是必须有的...

19410
来自专栏java思维导图

java基础思维导图,让java不再难懂

思维导图的好处 最近看了一些文章的思维导图,发现思维导图真是个强大的工具。了解了思维导图的作用之后,觉得把它运用到java上应该是个不错的想法,这样回顾知识点的...

5396
来自专栏撸码那些事

【抽象那些事】缺失抽象

这是一个笑脸,那么我们是怎么知道这是一个笑脸的呢?通过抽象。人脸数以亿计,却各不相同。我们忽略了不重要的细节,如发型和发色。我们还概括了相同的东西,每个人都有两...

44515
来自专栏玄魂工作室

Python黑帽编程 2.0 第二章概述

于 20世纪80年代末,Guido van Rossum发明了Python,初衷据说是为了打发圣诞节的无趣,1991年首次发布,是ABC语言的继承,同时也是一...

3637
来自专栏企鹅号快讯

C语言的前世今生,及其特点、利弊和入门须知三把斧

C语言的开展前史: ? 20世纪70年代初,贝尔实验室的Dennis Richie 等人在B语言基础上开发C语言,最初是作为UNIX的开发语言; 20世纪70年...

2116
来自专栏landv

C#本质论第四版-1,抄书才能看下去,不然两三眼就看完了,一摞书都成了摆设。抄下了记忆更深刻

4193

扫码关注云+社区