原型模式(Prototype Pattern)

大家熟知的原型链,也是按照原型模式进行。原型模式是一种创建对象的方式。今天我们就以JS的原型链作为主要讲解,通过原型链的实例继承和对象的创建。本文可能需要对JS原型链一定的了解,否则阅读本文可能会相对困难。

原型模式的实例

首先我们需要实现一个类,这个类可以通过clone的方法实现原型的创建对象,那么这个clone实际是就是实现了JS中的new的功能,因为JS对象的创建本来就是通过原型的方式实现而不是完全重现开辟空间。所以我们讲原型模式可以直接模拟JS类创建的方式即可。

  1. class Shape {
  2. constructor() {
  3. this.id = null;
  4. this.type = null;
  5. }
  6. getType(){
  7. return this.type;
  8. }
  9. getId() {
  10. return this.id;
  11. }
  12. setId(id) {
  13. this.id = id;
  14. }
  15. clone() {
  16. /**
  17. * 如果子类要改成class形式,这个方法要改写成下面形式
  18. * 因为主要是通过JS原型链帮助理解原型模式,所以子类不使用class形式
  19. * class和function构造函数的区别是class的构造函数增加了只能作为构造函数使用的校验,比如new
  20. * return Reflect.construct(
  21. * this.__proto__.constructor,
  22. * [],
  23. * this.__proto__.constructor
  24. * )
  25. */
  26. let clone = {};
  27. // 注意如果此类被继承,this会变成子类的方法
  28. // 同时这里使用的是原型的指针,所以比直接创建对象性能损耗更低
  29. clone.__proto__ = this.__proto__;
  30. this.__proto__.constructor.call(clone);
  31. return clone;
  32. }
  33. }

对于子类,原型链要实现继承是需要通过不断的追溯proto之上的对象作为继承的类,而prototype实例化之后会赋引用值到proto,所以要实现继承则是绑定prototype.proto作为追溯所得的结果之一。

  1. function Rectangle() {
  2. this.type = "Rectangle";
  3. }
  4. Rectangle.prototype.__proto__ = new Shape();
  5. Rectangle.prototype.draw = function() {
  6. console.log("I'm a rectangle")
  7. }
  8. function Square() {
  9. this.type = "Square";
  10. }
  11. Square.prototype.__proto__ = new Shape();
  12. Square.prototype.draw = function() {
  13. console.log("I'm a square")
  14. }
  15. function Circle() {
  16. this.type = "Circle";
  17. }
  18. Circle.prototype.__proto__ = new Shape();
  19. Circle.prototype.draw = function() {
  20. console.log("I'm a circle")
  21. }

在当前例子中,我们通过载入形状的cache的方式,再从cache中调用clone方法来实现原型创建的例子。

  1. class ShapeCache {
  2. static getShape(shapeId) {
  3. const cachedShape = ShapeCache.shapeMap.get(shapeId);
  4. return cachedShape.clone();
  5. }
  6. static loadCache() {
  7. const circle = new Circle();
  8. circle.setId("1");
  9. ShapeCache.shapeMap.set(circle.getId(),circle);
  10. const square = new Square();
  11. square.setId("2");
  12. ShapeCache.shapeMap.set(square.getId(),square);
  13. const rectangle = new Rectangle();
  14. rectangle.setId("3");
  15. ShapeCache.shapeMap.set(rectangle.getId(),rectangle);
  16. }
  17. }
  18. ShapeCache.shapeMap = new Map();
  19. ShapeCache.loadCache();
  20. const clonedShape = ShapeCache.getShape("1");
  21. console.log("Shape : " + clonedShape.getType());
  22. const clonedShape2 = ShapeCache.getShape("2");
  23. console.log("Shape : " + clonedShape2.getType());
  24. const clonedShape3 = ShapeCache.getShape("3");
  25. console.log("Shape : " + clonedShape3.getType());
  26. /**
  27. * output:
  28. * Shape : Circle
  29. * Shape : Square
  30. * Shape : Rectangle
  31. */

原型模式的优势

在其它编程中使用原型模式的优势是使用更小的代价来创建对象,通过原型引用的方式而不是开辟新的空间。但JS是个例外,直接new就好了,因为JS创建对象的方式就是原型引用,所以对比其它语言创建大对象的性能,能高出不少。

上一页(建造者模式)

下一页(适配器模式)