首页 > 解决方案 > 如何为整个服务提供一个单例实例?

问题描述

这就是我实现单例类的方式

import { AClient } from 'libbrary'
import { Container, Service } from 'typedi';

@Service()
class MyClass {
    private client: AClient;
    
    static getInstance(): MyClass {
        return Container.get(MyClass);
    }
    
    getClient(): AClient {
        if(this.client !== null){
            return this.client;
        }
        this.client = new AClient();
        return this.client;
    }
}

这里主要关注的是使用 Acliet()。
我正在通过以下方式实现这个客户端的方法。

class AClientMethodsImplementation {
    async getSomeData() {
        // I need client here so that I can use client.get()
    }
}

现在我应该在我的服务中使用这些方法。

class NeedDataHere {
    // Not only here, in the entire project I need this many places.
    // should I create AClientMethodsImplementation() instance everytime?
    // If that is the case what is the point of a singleton?
    // How to achieve this? What is the correct approach?
}

我是否遵循正确的方法?或者处理这种情况的最佳方法是什么?我说这是一个问题,因为我观察到AClientMethodsImplementation每次通过创建新类来点击 getSomeData() 都会给出相同的结果,即使我将输入数据更改为该函数也是如此。我怀疑它在某处缓存。

标签: typescriptoopdesign-patternssingletonclient

解决方案


这真的取决于你的情况。如果AClientMethodsImplementation是无状态的(它不会在方法调用之间保存与实例相关的数据),则应声明其所有成员static

class AClientMethodsImplementation {
    static async getSomeData() {
        AClient client = MyClass.getInstance().getClient();
    }
}

class NeedDataHere {
   
   // Call static methods
   let data = AClientMethodsImplementation.getSomeData();
}

如果AClientMethodsImplementation应该存储与实例相关的数据,您当然必须创建一个新实例(除非特定方法不会改变实例。在这种情况下它可以static)。
如果您希望此实例在整个应用程序中相同,则可以将其实现AClientMethodsImplementation为 Singleton。

单例模式的首选替代方案是使用依赖注入(IoC 模式的一种实现)。通过这种方式,您可以共享同一个实例,但不会牺牲松散耦合和可测试性。

通常,当您想在全局范围内使用单个对象状态(例如 cookie 之类的会话对象)时,您会使用共享实例(通过依赖注入或单例)。另一个用例是,由于资源分配或实例化过于耗时,实例化可能过于昂贵。然后,您分配一次资源,例如数据库/服务连接并重用它(共享资源)。另一个用例是提供对共享资源(例如数据缓存)的受控访问。例如,您通常在应用程序中使用共享记录器实例。

检查代码时,共享AClient实例的好处可能是提高性能。如果您可以说客户端公开了昂贵的共享资源或数据,或者通常太昂贵而无法创建它的多个实例,那么共享实例是值得的。显然,您仍然创建多个实例这一事实AClientMethodsImplementation不会使共享实例变得多余。


推荐阅读