媒介
本章我们要解说的是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一书中我们找到了接口的定义:
一个对象声明的恣意一个操纵都包含一个操纵称号,参数对象和操纵的返回值。我们称之为操纵符的署名(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顺序设想形式里依旧有它发挥作用的处所。
关于本文
本文转自TOM大叔的深切明白JavaScript系列。关于S.O.L.I.D
系列的五篇文章我纠结了良久,原本不想去整顿的,但终究发明实在中心说的许多都是关于OOP
(面向对象)编码准绳的东西,异常值得研读,所以末了照样决议整顿出来。这篇文章我至心以为大叔写的不怎么样。我看了好几遍也没看懂。正如大叔所言,看看就得。别陷得太深。
【深切明白JavaScript系列】文章,包含了原创,翻译,转载,整顿等各范例文章,原文是TOM大叔的一个异常不错的专题,现将其重新整顿宣布。感谢大叔。假如你以为本文不错,请帮助点个引荐,支撑一把,感激涕零。
更多优异文章迎接关注我的专栏