Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

继承 vs 组合

  当一种语言有了继承的概念后,到底用继承还是用组合的问题就会暴露出来。到网络上搜一波肯定能找到一堆纠结这个问题的人,但主要是 C++ 和 Java,很少有 JavaScript 开发者纠结这件事,因为一直以来 JavaScript 的继承并不是类继承,只有在 ES6 之后才有了 class。
  在 ES6 之前很少会有业务将自己的所有东西抽象成类来写,毕竟原型继承是非常简陋的,而且使用起来太麻烦。甚至很多号称几年 JavaScript 经验的开发者被问到原型继承的细节问题时也是答不出的。直到 ES6 之后,继承变得更容易使用。于是对于继承和组合之纠结就开始了。
  对于这个问题,很多人的解释就是 is 和 has 的区别。is 的逻辑就用继承,has 的逻辑就用组合。这是一句正确的废话,如果事务可以明确区分 is 和 has,开发人员当然直到该怎么玩。可是现实中往往有很多东西它既可以是 is 也可以是 has。比如 File 和 Blob 的关系,虽然浏览器是用继承来实现的,但就逻辑而言「file is blob」和「file has blob」都是正确的。
  那么到底该如何来界定继承和组合的使用范围呢?其实这个问题应该从具体的语言特性上来分析。比如 C++ 的那套就不适用于 Java,有些东西在 C++ 上可以用继承来实现,在 Java 上就不该用。因为 C++ 的语言特性是支持多重继承的,而 Java 只支持单继承。但是 Java 可以使用 interface/implements 来解决问题。
  现在再看 JavaScript 呢?什么都没有!那这个犊子应该怎么扯?首先我们需要一条基本定律,在程序设计上应该就是「高内聚、低耦合」了吧?继承是一种强耦合的交互方式,而组合可以在不破坏内聚的基础上让耦合更松。所以,我们应该优先使用组合,只有当组合的方案成本高到不能接受时才考虑使用继承。
  还是拿 File 和 Blob 为例,实际上它们被设计为继承关系是因为很多接口接收的参数都是 Blob 的,有了 File 这个类后又希望所有原本接收 Blob 的接口也支持 File。如果让所有接口都加上 File 类的支持显然是成本过高的方案,于是这里用了继承。最终在接口中的验证可以视为是 instanceof。
  这个例子可以抽象出更细的规则,当需要用到 instanceof、toString、valueOf 等这样对象特有属性的关系才需要用到继承,其它情况都应该使用组合。
网名:
50.16.97.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^