3

所以我想要一个名为的类client,它将成为我用 JavaScript 编写的视频游戏的基础。

client应该是一个只能有一个实例的类,但它的第一次创建应该由我自己在特定事件中设置,例如当用户单击“开始”按钮时。

我给自己做了一个单例类,我开始卸载它只是为了测试:

// Singleton class for the client
var client = (function() {

  // Public methods
  var _this = {
    construct: function() {
      delete _this.construct;
      _this.director = new lime.Director(document.body, window.innerWidth, window.innerHeight); // Setup the rendering engine
    }
  }
  return _this;
})();

// Fire when dependencies are loaded
window.onload = client.construct;

问题:

但我打算将其作为一个开源项目,最后一行client.construct似乎是一个非常不寻常的约定。我怎样才能编写我的单例类,以便它可以被构造new Client并且永远不能再次构造?

4

6 回答 6

7

首先:你确定你真的想这样做吗?对于大多数简单的情况,您可能最好不要打扰 aprototype或根本不使用new关键字,而只需使用您想要的属性和方法编写一个对象字面量 - 或者使用一次性函数创建一个对象(如果稍微多一点)需要复杂的构造逻辑。简单是好的。

我猜在某些情况下,您可能希望在 JavaScript 中创建一个“传统”单例 - 比如延迟实例化,或者如果您使用涉及单例类原型的经典继承。

在这种情况下,您可能想尝试这种基于 bfavaretto 的方法,在这种方法中,类的用户应该通过调用Client.getSingletonInstance()而不是来获取 Client 对象new Client(),并且 Client 的实例化new发生在getSingletonInstance()方法内部。

var Client = (function() {
    // Our "private" instance
    var instance;

    // The constructor
    function Client() {

        // If it's being called again, throw an error
        if (typeof instance != "undefined") {
            throw new Error("Client can only be instantiated once.");
        }

        // initialize here

        // Keep a closured reference to the instance
        instance = this;
    }

    // Add public methods to Client.prototype
    Client.prototype.myPublic = function() {

    }

    Client.getSingletonInstance = function() {
        if (typeof instance == "undefined") {
            return new this();
        }
        else {
            return instance;
        }
    }

    // Return the constructor
    return Client;
})();


var c1 = Client.getSingletonInstance();
var c2 = Client.getSingletonInstance();

console.log(c1 == c2); // true

我更喜欢这种方式,因为在我看来,让用户调用类new但实际上没有获得新对象是一种误导。

http://jsfiddle.net/hBvSZ/3/

于 2013-06-29T22:53:26.893 回答
3

您可以使用在常规面向对象语言中使用的相同模式:将实例存储在“私有”或“静态”属性中(我引用这些术语是因为它们并不完全适用于 JavaScript)。在代码中,这将是这样的,使用“私有”属性来存储实例(“静态”属性将是构造函数的属性):

var Client = (function() {
    // Our "private" instance
    var instance;

    // The constructor
    function Client() {

        // If it's being called again, return the singleton instance
        if(typeof instance != "undefined") return instance;

        // initialize here

        // Keep a closured reference to the instance
        instance = this;
    }

    // Add public methods to Client.prototype
    Client.prototype.myPublic = function() {

    }

    // Return the constructor
    return Client;
})();


var c1 = new Client();
var c2 = new Client();

console.log(c1 == c2); // true

http://jsfiddle.net/hBvSZ/

于 2013-06-29T22:38:42.690 回答
1

像这样的东西:

var Client = (function ClientClass(){

  var instance;

  // Constructor
  function Client() {
    if (instance) throw 'Already instantiated';
    this.director = new lime.Director(...);
    instance = true;
  }

  Client.prototype = {
    // Public methods
  };

  return Client;

}());
于 2013-06-29T22:33:43.180 回答
0

这可能是你想要的:

var initialized = false;

function initialize() {
    if (!initialized) {
        window.client = new Client();
        initialized = true;
    }
}

window.onload = initialize;
于 2013-06-29T22:17:19.577 回答
0

你没有。在强类型语言中,单例是通过具有私有构造函数并公开包含该类的唯一实例的静态属性来创建的。为了防止第二次实例化,您唯一可以做的就是抛出异常,但这是更糟糕的设计。但是,您可能会延迟实例化您的对象:

// A wrapper function
var client = (function () {
    var client = function() {
       // Actual class
    }
    var instance = null;
    // Property to return the instance
    Object.defineProperty("instance", {
        get: function () {
            if (!instance) { instance = new client(); }
            return instance;
        }
    }
   return client;
})();
于 2013-06-29T22:18:17.657 回答
0

这是我最喜欢的单例模式,它简单明了:

var mySingleton = new function() {
    // ...
}

所以你可以这样做:

var myClient = new function() {
    this.director = null;
    this.initialize = function() {
        // Setup the rendering engine
        this.director = new lime.Director(
            document.body, 
            window.innerWidth, 
            window.innerHeight
        );
    }
}

window.onload = myClient.initialize();

资料来源:Alexander Podgorny 的单例模式

于 2013-06-29T22:21:46.117 回答