基于原型的对象导向。好的,不好的和丑陋的呢?

我来自基于类的面向对象语言,最近我一直在学习那些花哨的动态语言(JavaScript、Python 和 Lua),我想知道在这些语言中如何使用面向对象编程。了解此方法的缺点和问题以及与传统面向对象的优势将会很有用。

我的一般理解是:基于原型的面向对象编程基本上是与对象一起编程,但没有关于如何使用它们的标准,而在普通的面向对象编程中,有一个固定的预定义方式来创建和使用对象。

总之,这种方法的好处、坏处和丑陋的部分是什么?

原文链接 https://stackoverflow.com/questions/385403

点赞
stackoverflow用户35092
stackoverflow用户35092

原型模型的类

首先,实际上原型模型并不是很不同。Smalltalk 使用一种类似的方案,即将类看作是一个具备类方法的对象。

从类的角度来看,一个类实际上是具有相同数据和方法的对象等价类。将方法添加到原型中可以看作是创建一个新的子类。

这种实现方式简单,但很难有效地进行类型检查。

2008-12-22 02:31:15
stackoverflow用户26394
stackoverflow用户26394

为了保护带宽,这里提供了链接来查看我的回答:“如何在JavaScript中模拟‘类’?(使用或不使用第三方库)” ,它包含进一步的参考和实例。

简短的回答是:JavaScript原型对象(OO)的核心是委派。在这种面向对象编程(OOP)模式中,相同“类”的不同对象可以将方法和属性的处理委派给相同的原型(通常是一些第三方对象):

var foo = {
    property: 42,
    inc: function(){
        ++this.counter;
    },
    dec: function(){
        --this.counter;
    }
};
// 注意:foo没有定义“counter”。

让我们创建一个构造函数,它的原型是foo。实际上,未处理的所有内容都将委派给foo。

var Bar = function(){
    this.counter = 0;
};
Bar.prototype = foo;  // 这就是我们设置委派的方式。

// 有些人将Bar(构造函数)称为“类”。

var bar = new Bar();

console.log(bar.counter);  // 0 --- 来自bar自身
console.log(bar.property); // 42 --- 没有在bar中定义,在foo中定义

bar.inc();  // 在bar中未定义 => 委托给foo
bar.inc();
bar.dec();  // 在bar中未定义 => 委托给foo
// 注意:foo.inc()和foo.dec()调用,但this === bar,
// 这就是bar被修改,而不是foo。

console.log(bar.counter);  // 1 --- 来自bar自身

让我们在bar上直接定义inc()

bar.inc = function(){
    this.counter = 42;
};

bar.inc();  // 在bar中定义 => 直接调用它。
            // 甚至foo.inc()都未被调用。
console.log(bar.counter);  // 42 --- 来自bar

设置单一继承链:

var Baz = function(){
    this.counter = 99;
};
Baz.protype = new Bar();

var baz = new Baz();

console.log(baz.counter); // 99
baz.inc();
console.log(baz.counter); // 100

console.log(baz instanceof Baz);    // true
console.log(baz instanceof Bar);    // true
console.log(baz instanceof Object); // true

很好吧,对吧?

2008-12-22 03:15:34
stackoverflow用户41661
stackoverflow用户41661

Prototype-based OO 不太适合静态类型检查,有些人可能会认为这是坏的或丑陋的。Prototype-based OO _有_一种创建新对象的标准方法,你可以克隆和修改现有的对象,也可以构建工厂等。

我认为人们最喜欢的(“好的”)是基于原型的 OO 非常轻量级和灵活,提供了非常高的功率与重量比

关于如何使用基于原型的 OO 的提示,一个很好的起点是原始 Self 论文上的 简单之力

2008-12-22 04:34:49
stackoverflow用户8482
stackoverflow用户8482

在担心如何在 JavaScript 中模拟基于类的继承之前,先快速阅读一下 _JavaScript 中的原型继承_。

2009-01-03 00:50:41
stackoverflow用户279738
stackoverflow用户279738

经典继承在灵活性方面存在缺陷,因为我们要说“这个对象属于这种类型,没有其他类型”。有些语言引入多重继承以减轻这种问题,但多重继承也有其自身的问题,因此在继承方面,纯组合优于继承的好处变得明显(在静态类型语言中,它是一种运行时而不是编译时机制)。

将组合概念推展到“纯净”程度,我们可以完全消除经典继承和静态类型。通过在运行时组合对象并将其用作蓝图(原型方法),我们不必通过继承过度约束对象,并且也不必担心多重继承方法固有的问题。

因此,原型方法意味着模块的开发变得更加灵活。

当然,说没有静态类型就容易开发是另一回事。在我看来,这是不可能的。

2010-10-18 10:31:26