Kar*_*ari 6 javascript singleton design-patterns javascript-objects typescript
我有一个TypeScript单例类
class MySingleton {
private static _instance: MySingleton;
private constructor();
public static getInstance() {
if (!MySingleton._instance) {
MySingleton._instance = new MySingleton();
}
return MySingleton._instance;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我想在创建这个单例实例时传递一些选项.
例如,将实例的模式设置为生产模式的选项.
因此,可以通过getInstance接受传播到构造函数的选项对象来实现.然后使用变得像
MySingleton.getInstance({
prodMode: true
});
Run Code Online (Sandbox Code Playgroud)
这是最好的方法吗?这样做有点蠢,因为当通过传递选项对象MySingleton执行的消费者时getInstance,他或她无法知道传递的选项对象将被使用或被忽略.
在 TypeScript 中,就像在 JavaScript 中一样,单例模式并不存在,正如您在 Java 或其他语言中可能知道的那样。
为什么我们没有相同的概念?
因为对象和类不是相互依赖的。
首先我们问自己什么是单例?
在整个应用程序中全局只能有一个实例的类。
在 TypeScript 中,您可以通过创建全局变量来做到这一点。
例如:
// at global scope
var instance = {
prodMode: true
};
Run Code Online (Sandbox Code Playgroud)
或从模块内:
globalThis.instance = {
prodMode: true
};
declare global {
var instance: {
prodMode: boolean
};
}
Run Code Online (Sandbox Code Playgroud)
就在那里,没有类,没有锁或守卫,只是一个全局变量。
上述方法具有以下额外优点(就在我的脑海中):
现在您可能会回答说您需要或至少想要上课。
没问题:
globalThis.instance = new class {
prodMode = true
}();
Run Code Online (Sandbox Code Playgroud)
但请不要将类用于简单的配置对象。
现在开始配置实例的用例:
如果你想要一个可配置的单例,你应该仔细考虑你的设计。
但是,如果经过深思熟虑,似乎有必要创建一个全局构造函数,请考虑以下调整:
namespace singleton {
class Singleton_ {constructor(options: {}){}}
export type Singleton = Singleton_;
var instance: Singleton = undefined;
export function getInstance(options: {}) {
instance = instance || new Singleton_(options);
return instance;
}
Run Code Online (Sandbox Code Playgroud)
上述使用 IIFE 模式(TypeScript namespace)的方法具有以下优点:
private constructor来阻止外部实例化。instance.constructor这是避免使用类并使用前面所述的简单对象的另一个原因)。class可以在运行时破坏单例模式的方式进行扩展或误用(尽管它是可访问的,因为这是instance.constructor避免使用类并使用前面描述的简单对象的另一个原因)。但正如你所说,将选项传递给getInstance函数会使 API 变得不清楚。
如果目的是允许更改实例,只需公开重新配置方法(或只是使对象可变)。
globalThis.instance = {
prodMode: true,
reconfigure(options) {
this.prodMode = options.prodMode;
}
};
Run Code Online (Sandbox Code Playgroud)
评论:
JavaScript 中众所周知的单例的一些示例包括
全局变量通常很糟糕,而可变全局变量通常更糟糕。
模块可以在这里提供帮助。
就我个人而言,由于我使用模块,如果我想要一个不同的全局对象,具体取决于“正在生产”之类的值,我会写
// app.ts
export {}
(async function run() {
const singletonConditionalModuleSpecifer = prodMode
? "./prod-singleton"
: "./dev-singleton";
const singleton = await import(singletonConditionalModuleSpecifer);
// use singleton
}());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
692 次 |
| 最近记录: |