添加'假'使用强制初始化方法的单例包装器到Node类

时间:2015-11-19 21:12:00

标签: javascript node.js

(免责声明:删除了导致一些新的基本问题的先前问题,因此再次尝试更明智的问题)。

我有一个具有一些必需初始化属性的类:

var CustomRequest = require('./request'),
    ok = require('objectkit'),
    helpers = require('../helpers')

var MySDKClient = function(orgId, appId) {
    var self = this
    if (ok(orgId).exists() && ok(appId).exists()) {
        self.orgId = orgId
        self.appId = appId
        return self
    } else {
        throw new Error('orgId and appId must be passed during initialization')
    }
}

MySDKClient.prototype = {
    GET: function(uri, options, callback) {
        return new CustomRequest('GET', uri, options, callback)
    }
}

// Exports
module.exports = MySDKClient

这样就像这样:

var MySDKClient = require('./lib/client')
var client = new MySDKClient('orgId', 'appId')

但是我需要将它包装在 new 类中,它包含MySDKClient的单个实例并继承其所有方法/属性。我们称之为MySDK,它需要有一个自定义初始化方法:

var MySDK = require('./mysdk')
MySDK.initialize('orgId', 'appId')
module.exports = MySDK

(或不太喜欢):

var MySDK = require('./lib/client').initialize('orgId', 'appId')
module.exports = MySDK

如果初始化方法有MySDKClient,我希望它无法通过throw中的MySDKClient初始化(因此无法调用任何var MySDK = require('./lib/client') MySDK.initialize('orgId', 'appId') MySDK.GET('...') // should work! 方法)没被打电话。

例如,这应该有效:

var MySDK = require('./lib/client')
MySDK.GET('...') // should throw error because of 'throw new Error()` 
                 // that already exists in MySDKClient -- more accurately, 
                 // MySDK should be null or undefined because it wasn't initialized.

这不应该:

util.inherits()

我该怎么做?我尝试使用Object.create()// mysdk.js var MySDKClient = require('./lib/client'), ok = require('objectkit'), helpers = require('./helpers'), util = require("util") function MySDK() { // new MySDKClient? } MySDK.prototype = { initialize: function(orgId, appId) { return new MySDKClient(orgId, appId) } } // Should I still be doing this? // util.inherits(MySDK, MySDKClient) // Exports module.exports = new MySDK 来创建子类',但无论我做什么,MySDKClient类的原型方法都不是&n;无论客户端是否已正确初始化,它们都可以使用。

更新:尝试@ sg.cc的解决方案,MySDKClient的行为与以前相比更好/更少,但我仍然无法在模块中正确启动MySDK实例:

var MySDK = require('./mysdk')
MySDK.initialize('peter', 'wolf')
MySDK.GET() // undefined is not a function

致电:

{{1}}

2 个答案:

答案 0 :(得分:2)

你需要停止思考类,并开始接受javascript的原型继承。另外,请尝试将代码片段简化为最低限度,以便于重现。

我简化了您的再现性示例,但以下内容应指向正确的方向:

这是我简化的MySDKClient构造函数:

var MySDKClient = function(orgId) { this.orgId = orgId; } 
MySDKClient.prototype.GET = function() { alert(this.orgId); }

您的MySDK不一定是构造函数(如果您愿意,也可以是class):

var MySDK = { 
  initialize: function(orgId) { 
    Object.setPrototypeOf(MySDK, new MySDKClient(orgId)) 
  } 
}

在控制台中试用:

MySDK.GET()

会抛出错误,因为当解释器走向MySDK的原型链时,它找不到GET函数。

现在,如果您调用MySDK.initialize(10);,则会修改对象的原型链以包含MySDKClient。现在如果你运行MySDK.GET(),你会看到10被警告。

虽然Object.setPrototypeOf是对javascript的新增功能,但使用polyfill可以使用非常简单的Object.prototype.__proto__,可用于几乎所有主要平台

答案 1 :(得分:1)

var CustomRequest = require('./request'),
  ok = require('objectkit'),
  helpers = require('../helpers')   



var MySDKClient = function(org, app){
  return (function init(orgId, appId) {
    var init = false;
    if( ok(orgId).exists() && ok(appId).exists() ) {
      this.orgId = orgId;
      this.appId = appId;
      init = true;
    } else {
      throw new Error('orgId and appId must be passed during initialization')
    }
    if( !init ) return;
    return {
      GET: function(uri, options, callback){
        // Where are you using orgId that customRequest needs to fail if they aren't present?
        return new CustomRequest('GET', uri, options, callback);
      }
    }
  })(org, app);
}

module.exports = MySDKClient;

测试:

var MySDK = require('./lib/client');

var a = MySDK(123, abc);
var b = MySDK(); // -> Exception thrown
a.GET(some, args, here); // Works
b.GET(some, args, here); // property GET of undefined is not a function