【问题标题】:ES6: Restricting the Base Class to a SingletonES6:将基类限制为单例
【发布时间】:2017-05-27 21:39:37
【问题描述】:

我在一个超类(基类)之外有两 (2) 个子类;如果我新建 B 和 C,我会得到两个实例——它们都通过扩展包含基类。

问题:是否可以对 super 设置 Singleton 限制 类,如果是,怎么做?

class A {
  constructor(id) {
    // => I don't want to make this call (2) times, 
    //  once for B and again for C.
    let {
      firstName: this._FirstName 
    } = CollectionName.findOne({userId: id}); 
  }
}

export class B extends A {
  constructor(id) {
    super(id);
  }
  get FirstName() {
    return this._FirstName;
  }
}

export class C extends A {
  constructor(id) {
    super(id);
  }
  get FirstName() {
    return this._FirstName;
  }
}



import { B, C } from 'imports/server/a-b-c.js'

const b = new B('123')

const c = new B('456')

const FirstNameB = b.FirstName;

const FirstNameC = c.FirstName;

编辑:

我将尝试在这里回答问题。

@卡西莫多的克隆:你有一个单例模式的意图是什么?您是否只是怀疑子类化是否可以生成多个超类实例?或者您是否尝试防止多个子类实例 - 超类应该强制新 C 始终返回同一个 C 实例?

基类调用 MongoDB 并检索大量数据(如果只有一个类,它就是基类)。当我有两个类扩展一个基类时,我不想调用 Mongo 并多次存储所有这些数据。 ATM 我使用单例模式来防止这种情况发生在单独的类中,但我真的很想在我有两个使用相同基类的类的情况下使用这种模式。

换个说法, 我已经验证的问题正在发生:当我有两个类调用一个基类时,基类的构造函数被调用了两次,Mongo 被击中了两次。 ATM 当它被扩展调用时,我没有为基类设置单例模式。

现在我需要弄清楚如何在由多个类扩展的基类上应用单例模式。而且由于基类实际上是子类的同一个实例,我什至不知道这是否可能。

【问题讨论】:

  • 虽然超过 1 个关于 SO 的问题应该发布在多个不同的帖子中以适应 SO Q/A 格式...你打算使用单例模式是什么?您是否只是怀疑子类化是否可以生成多个超类实例?或者您是否尝试阻止多个子类实例 - 超类应该强制 new C 始终返回同一个 C 实例?
  • 使用每个new 创建一个实例(this)。这就是new 的目的,这个名字说明了一切。一个类是否继承另一个类并不重要。
  • @estus 即使违背语义,JS 确实提供了通过简单地编写return someObject; 来覆盖构造函数默认返回的能力。然而,由于原型概念的设计,我不相信有人能找到一种棘手的方法来阻止子类的构造函数被执行。您需要在最终类中实现单例模式。后者绝对是可能的。或者实现可以在超类中完成,只要它是从子类的构造函数中调用的。 example
  • @Quasimodo'sclone 我不是在谈论构造函数返回,而是在谈论默认行为。问题 1 可能是由于 OP 对他之前的问题的误解,即 super class 有它自己的 this。当然,如果 super 返回一个单例,无论是直接实例化还是从子类实例化,都只会有 1 个实例。

标签: javascript ecmascript-6 javascript-objects es6-class


【解决方案1】:

让我们首先生成一些测试输出到控制台。您应该在浏览器中运行它以获得功能齐全的控制台访问权限:

class Base
{
    constructor(value)
    {
        this.prop = value;
    }

    funcBase() {}
}

class B extends Base
{
    constructor(value)
    {
        super(value);
    }

    funcB() {}
}

class C extends Base
{
    constructor(value)
    {
        super(value);
    }

    funcC() {}
}

let
    b = new B('instance b'),
    b2= new B('instance b'),
    c = new C('instance c')
;

// Do instances of class B and class C have the identical prototype?
console.log( 'proto(b) === proto(c)',
              Object.getPrototypeOf(b) === Object.getPrototypeOf(c)  );
              // false

// Do the prototypes of those instances b and c have the idendical prototype?
console.log( 'proto-proto(b) === proto-proto(c)',
              Object.getPrototypeOf(Object.getPrototypeOf(b)) === Object.getPrototypeOf(Object.getPrototypeOf(c)) );
              //true

// Do two instances of class B have the identical prototype?
console.log( 'proto(b) === proto(b2)',
              Object.getPrototypeOf(b) === Object.getPrototypeOf(b2) );
              // true

// Is b's prototype's prototype identical to Base.prototype?
console.log( 'proto-proto(b) === Base.prototype',
  Object.getPrototypeOf(Object.getPrototypeOf(b)) === Base.prototype );
//true

// Let's inspect the prototypes in the console
// What is the prototype of b
console.log( Object.getPrototypeOf(b) );                        // an instance with constructor B() and funcB()

// What is the b's prototype's prototye?
console.log( Object.getPrototypeOf(Object.getPrototypeOf(b)) ); // an instance with constructor Base() and funcBase()

// Inspect constructor function B()
try      { console.dir( B ); }
catch(e) { console.log( B ); }  // [right click the "B" in the output and open in variable inspector]

如您所见,class 关键字实际上为您编译了一个构造函数和一个原型实例。 该实例由其prototype 属性中的构造函数引用。如果它扩展了超类,则原型的原型将与超类构造函数的prototype 属性相同(请参阅下面的__proto__ 属性)。当你创建 使用关键字new 的 B 类的新实例,创建一个新对象并引用原型 由构造函数分配给新对象的原型。大多数浏览器在__proto__ 属性中公开实例的原型。但是,您应该通过Object.getPrototype 方法访问它。

在检查器中,您可以使用__proto__ 属性遍历树。

因此,您的问题的答案是:您不需要单例设计模式,因为相同的原型 一旦在构造函数创建时实例化,每次使用关键字 new 创建新的时都会重用 实例。您可以在比较 Object.getPrototypeOf(Object.getPrototypeOf(b)) === Object.getPrototypeOf(Object.getPrototypeOf(c)) ) 时看到示例中的行为。两个原型链都引用相同的超类实例。

您应该阅读有关 JavaScript 原型设计概念的更多文档。它可能看起来非常复杂和奇怪,尤其是当您来自典型的 OOP 语言时,但它基于非常简单的设计。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    相关资源
    最近更新 更多