深入理解JavaScript系列(21):S.O.L.I.D五大原则之接口隔离原则ISP详解_基础知识
前言
本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第4篇,接口隔离原则ISP(The Interface Segregation Principle)。
英文原文:http://freshbrewedcode.com/derekgreer/2012/01/08/solid-javascript-the-interface-segregation-principle/
注:这篇文章作者写得比较绕口,所以大叔理解得也比较郁闷,凑合着看吧,别深陷进去了
接口隔离原则的描述是:
Clients should not be forced to depend on methods they do not use.
不应该强迫客户依赖于它们不用的方法。
当用户依赖的接口方法即便只被别的用户使用而自己不用,那它也得实现这些接口,换而言之,一个用户依赖了未使用但被其他用户使用的接口,当其他用户修改该接口时,依赖该接口的所有用户都将受到影响。这显然违反了开闭原则,也不是我们所期望的。
接口隔离原则ISP和单一职责有点类似,都是用于聚集功能职责的,实际上ISP可以被理解才具有单一职责的程序转化到一个具有公共接口的对象。
JavaScript接口
JavaScript下我们改如何遵守这个原则呢?毕竟JavaScript没有接口的特性,如果接口就是我们所想的通过某种语言提供的抽象类型来建立contract和解耦的话,那可以说还行,不过JavaScript有另外一种形式的接口。在Design Patterns – Elements of Reusable Object-Oriented Software一书中我们找到了接口的定义:
http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612
一个对象声明的任意一个操作都包含一个操作名称,参数对象和操作的返回值。我们称之为操作符的签名(signature)。
一个对象里声明的所有的操作被称为这个对象的接口(interface)。一个对象的接口描绘了所有发生在这个对象上的请求信息。
不管一种语言是否提供一个单独的构造来表示接口,所有的对象都有一个由该对象所有属性和方法组成的隐式接口。参考如下代码:
var exampleBinder = {};
exampleBinder.modelObserver = (function() {
/* 私有变量 */
return {
observe: function(model) {
/* 代码 */
return newModel;
},
onChange: function(callback) {
/* 代码 */
}
}
})();
exampleBinder.viewAdaptor = (function() {
/* 私有变量 */
return {
bind: function(model) {
/* 代码 */
}
}
})();
exampleBinder.bind = function(model) {
/* 私有变量 */
exampleBinder.modelObserver.onChange(/* 回调callback */);
var om = exampleBinder.modelObserver.observe(model);
exampleBinder.viewAdaptor.bind(om);
return om;
};
上面的exampleBinder类库实现的功能是双向绑定。该类库暴露的公共接口是bind方法,其中bind里用到的关于change通知和view交互的功能分别是由单独的对象modelObserver和viewAdaptor来实现的,这些对象从某种意义上来说就是公共接口bind方法的具体实现。
尽管JavaScript没有提供接口类型来支持对象的contract,但该对象的隐式接口依然能当做一个contract提供给程序用户。
ISP与JavaScript
我们下面讨论的一些小节是JavaScript里关于违反接口隔离原则的影响。正如上面看到的,JavaScript程序里实现接口隔离原则虽然可惜,但是不像静态类型语言那样强大,JavaScript的语言特性有时候会使得所谓的接口搞得有点不粘性。
堕落的实现
在静态类型语言语言里,导致违反ISP原则的一个原因是堕落的实现。在Java和C#里所有的接口里定义的方法都必须实现,如果你只需要其中几个方法,那其他的方法也必须实现(可以通过空实现或者抛异常的方式)。在JavaScript里,如果只需要一个对象里的某一些接口的话,他也解决不了堕落实现这个问题,虽然不用强制实现上面的接口。但是这种实现依然违反了里氏替换原则。
var rectangle = {
area: function() {
/* 代码 */
},
draw: function() {
/* 代码 */
}
};
var geometryApplication = {
getLargestRectangle: function(rectangles) {
/* 代码 */
}
};
var drawingApplication = {
drawRectangles: function(rectangles) {
/* 代码 */
}
};
当一个rectangle替代品为了满足新对象geometryApplication的getLargestRectangle 的时候,它仅仅需要rectangle的area()方法,但它却违反了LSP(因为他根本用不到其中drawRectangles方法才能用到的draw方法)。
静态耦合
静态类型语言里的另外一个导致违反ISP的原因是静态耦合,在静态类型语言里,接口在一个松耦合设计程序里扮演了重大角色。不管是在动态语言还是在静态语言,有时候一个对象都可能需要在多个客户端用户进行通信(比如共享状态),对静态类型语言,最好的解决方案是使用Role Interfaces,它允许用户和该对象进行交互(而该对象可能需要在多个角色)作为它的实现来对用户和无关的行为进行解耦。在JavaScript里就没有这种问题了,因为对象都被动态语言所特有的优点进行解耦了。
语义耦合
导致违反ISP的一个通用原因,动态语言和静态类型语言都有,那就是语义耦合,所谓语义耦合就是互相依赖,也就是一个对象的行为依赖于另外一个对象,那就意味着,如果一个用户改变了其中一个行为,很有可能会影响另外一个使用用户。这也违反单一职责原则了。可以通过继承和对象替代来解决这个问题。
可扩展性
另外一个导致问题的原因是关于可扩展性,很多人在举例的时候都会举关于callback的例子用来展示可扩展性(比如ajax里成功以后的回调设置)。如果想这样的接口需要一个实现并且这个实现的对象里有很多熟悉或方法的话,ISP就会变得很重要了,也就是说当一个接口interface变成了一个需求实现很多方法的时候,他的实现将会变得异常复杂,而且有可能导致这些接口承担一个没有粘性的职责,这就是我们经常提到的胖接口。
总结
JavaScript里的动态语言特性,使得我们实现非粘性接口的影响力比静态类型语言小,但接口隔离原则在JavaScript程序设计模式里依然有它发挥作用的地方。

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Vivo尚未公开宣布X100继任者的名称,但其官方微博简介上的各种预告片已经在谈论下一代旗舰相机,特别是将取代索尼IMX9的传感器技术

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。
