在阅读了两者之后,我只是好奇,编程社区如何使用它?在什么情况下哪个?
经典与原型继承
经典继承有很多原型继承不存在的问题,例如:
经典传承
紧耦合。继承是面向对象设计中可用的最紧密的耦合。后代类对其祖先类有深入的了解。
不灵活的层次结构(也就是必要的重复)。单父层次结构很少能够描述所有可能的用例。最终,所有层次结构对于新用途都是“错误的”——这个问题需要重复代码。
多重继承很复杂。从多个父母那里继承通常是可取的。该过程异常复杂,其实现与单继承的过程不一致,这使得阅读和理解变得更加困难。
脆弱的架构。由于紧密耦合,通常很难重构具有“错误”设计的类,因为许多现有功能依赖于现有设计。
大猩猩/香蕉问题。通常,您不想继承父代的某些部分。子类化允许您覆盖父级的属性,但不允许您选择要继承的属性。
原型继承
要了解原型继承如何解决这些问题,您首先应该了解原型继承有两种不同的类型。JavaScript 同时支持:
委托。如果在实例上找不到属性,则会在实例的原型上搜索它。这使您可以在许多实例之间共享方法,免费为您提供享元模式。
串联。向对象动态添加属性的能力使您能够将任何属性从一个对象自由复制到另一个对象,一起或有选择地复制。
您可以结合两种形式的原型继承来实现非常灵活的代码重用系统。事实上,如此灵活,以至于用原型实现经典继承是微不足道的。反过来就不对了。
原型继承允许您在经典语言中找到的大多数重要功能。在 JavaScript 中,闭包和工厂函数允许您实现私有状态,并且函数继承可以轻松地与原型结合,以便添加支持数据隐私的 mixin。
原型继承的一些优点:
松耦合。实例永远不需要直接引用父类或原型。可以存储对对象原型的引用,但不建议这样做,因为这会促进对象层次结构中的紧密耦合——经典继承的最大缺陷之一。
扁平的层次结构。使用原型 OO 保持继承层次结构平坦是微不足道的 - 使用串联和委托,您可以拥有单一级别的对象委托和单个实例,而无需对父类的引用。
琐碎的多重继承。从多个祖先继承就像使用串联组合来自多个原型的属性一样简单,以形成一个新对象,或一个新对象的新委托。
灵活的架构。由于您可以使用原型 OO 有选择地继承,因此您不必担心“错误设计”的问题。新类可以从源对象的任何组合继承任何属性组合。由于层次结构扁平化很容易,一个地方的变化不一定会在整个后代对象的长链中引起涟漪。
没有大猩猩了。选择性继承消除了大猩猩香蕉问题。
我不知道经典继承比原型继承有什么优势。如果有人知道,请赐教。
基于原型的继承更加灵活。任何现有的对象都可以成为一个类,从中可以产生其他对象。当您的对象提供多组服务和/或在您的程序到达需要继承的点之前它们经历了大量状态转换时,这很方便。
建模方法的广泛讨论可在此处获得:http : //steve-yegge.blogspot.com/2008/10/universal-design-pattern.html
由于 Javascript 不支持大多数人理解的“经典”继承(并且您没有对您正在阅读的内容提供任何参考),我假设您的意思是继承处理如下:-
function base() {
var myVar;
this.someBaseFunc = function() { }
}
function derived() {
base.call(this);
var someOtherVar;
this.SomeOtherFunc = function() { }
}
我的一般经验法则是:
- 如果类很复杂并且实例很少,则使用“经典”方法。这允许类仅公开那些应该公开的功能。
- 如果类很简单并且实例很多,则使用原型方法。这限制了在创建实例时反复定义和存储对函数的引用的开销。