Skip to main content

原型模式(创建型)

原型模式 —— 谈 Prototype 无小事

原型模式不仅是一种设计模式,还是一种编程范式(programming paradigm),是 JavaScript 面向对象系统实现的根基。

在原型模式下创建对象时,会先找到一个对象作为原型,然后通过克隆原型的方式来创建出一个与原型一样(共享一套数据/方法)的对象。在 JavaScript 中,Object.create 方法是原型模式的天然实现——准确地说,借助 Prototype 来实现对象的创建和原型的继承,就是在应用原型模式。

在 JavaScript 中使用原型模式,并不是为了得到一个副本,而是为了得到与构造函数(类)相对应的类型的实例、实现数据/方法的共享。克隆是实现这个目的的方法,但克隆本身并不是我们的目的。

一、以类或原型为中心的语言

1、Java 中的类

原型模式是 JavaScript 这门语言面向对象系统的根本。

但在 JAVA 中,类才是它面向对象系统的根本。所以 JAVA 可以选择不使用原型模式 —— 这样所有的实例都要从类中来,当创建两个一模一样的实例时,可以这样

假设实例从 Dog 类中来,必传参数为姓名、性别、年龄和品种:

Dog dog = new Dog('旺财', 'male', 3, '柴犬')
Dog dog_copy = new Dog('旺财', 'male', 3, '柴犬')

可以看到,需要把一模一样的参数传两遍,非常麻烦。

而原型模式可以通过调用克隆方法的方式达到同样的目的,比较方便,所以 Java 专门针对原型模式设计了一套接口和方法,在必要的场景下会通过原型方法来应用原型模式。当然,在更多的情况下,Java 仍以“实例化类”这种方式来创建对象。

2、 JavaScript 中的类

由于 ES6 的类是基于原型继承的语法糖,所以 ES6 Class 类语法不会为 JavaScript 引入新的面向对象的继承模型。

当我们尝试用 class 去定义一个 Dog 类时:

class Dog {
constructor(name, age) {
this.name = name;
this.age = age;
}

eat() {
console.log("肉骨头真好吃");
}
}

其实等价于写了这么一个构造函数:

function Dog(name, age) {
this.name = name;
this.age = age;
}

Dog.prototype.eat = function () {
console.log("肉骨头真好吃");
};

所以说 JavaScript 的根本是原型模式。在 Java 等强类型语言中,原型模式的出现是为了实现类型之间的解耦。而 JavaScript 本身类型就比较模糊,不存在类型耦合的问题,所以平时不会刻意地去使用原型模式。因此在 JS 中把原型模式作为一种编程范式来讨论会更合适。

二、谈原型模式,其实是谈原型范式

原型编程范式的核心思想是利用实例来描述对象,用实例作为定义对象和继承的基础。在 JavaScript 中,原型编程范式的体现就是基于原型链的继承。

点击查看原型和原型链详情

三、模拟 Java 中的克隆接口

模拟 Java 中的克隆接口,就是实现 JavaScript 原型模式,即实现深拷贝。

点击查看深拷贝详情