简体   繁体   English

什么是单身人士的替代品

[英]What's Alternative to Singleton

We have a class that holds configuration information for the application. 我们有一个类,用于保存应用程序的配置信息。 It used to be a singleton. 它曾经是一个单身人士。 After some architectural review, we were told to remove the singleton. 经过一些建筑评论后,我们被告知要删除单身人士。 We did see some benefits of not using singleton in the unit testing because we can test different configurations all at once. 我们确实看到了在单元测试中不使用单例的一些好处,因为我们可以同时测试不同的配置。

Without singleton, we have to pass the instance around everywhere in our code. 如果没有单例,我们必须在代码中的任何地方传递实例。 It's getting so messy so we wrote a singleton wrapper. 它变得如此混乱,所以我们编写了一个单独的包装器。 Now we are porting the same code to PHP and .NET, I am wondering if there is a better pattern we can use for the configuration object. 现在我们将相同的代码移植到PHP和.NET,我想知道是否有更好的模式我们可以用于配置对象。

The Google Testing blog has a series of entries about avoiding Singleton (in order to create testable code). Google测试博客有一系列关于避免使用Singleton的条目(为了创建可测试的代码)。 Maybe this can help you: 也许这可以帮助你:

The last article explains in detail how to move the creation of new objects into a factory, so you can avoid using singletons. 上一篇文章详细解释了如何将新对象的创建移动到工厂中,因此您可以避免使用单例。 Worth reading for sure. 值得一读。

In short we move all of the new operators to a factory. 简而言之,我们将所有新运营商转移到工厂。 We group all of the objects of similar lifetime into a single factory. 我们将具有相似生命周期的所有对象组合到一个工厂中。

The best way is to use a Factory pattern instead. 最好的方法是使用Factory模式。 When you construct a new instance of your class (in the factory) you can insert the 'global' data into the newly constructed object, either as a reference to a single instance (which you store in the factory class) or by copying the relevant data into the new object. 构造类的新实例(在工厂中)时,可以将“全局”数据插入到新构造的对象中,作为对单个实例的引用(存储在工厂类中)或通过复制相关实例数据进入新对象。

All your objects will then contain the data that used to live in the singleton. 然后,所有对象都将包含以前在单例中存在的数据。 I don't think there's much of a difference overall, but it can make your code easier to read. 我认为总体上没有太大差异,但它可以使您的代码更容易阅读。

I might be stating the obvious here, but is there a reason why you can't use a dependency-injection framework such as Spring or Guice ? 我可能在这里说明显而易见的,但是有没有理由不能使用像SpringGuice这样的依赖注入框架? (I believe Spring also is available for .NET as well now). (我相信Spring现在也可用于.NET)。

That way, the framework can hold a single copy of the configuration objects, and your beans (services, DAOs, whatever) don't have to worry about looking it up. 这样,框架可以保存配置对象的单个副本,并且您的bean(服务,DAO,等等)不必担心查找它。

This is the approach I usually take! 这是我经常采取的方法!

If you use Spring Framework , you can just create a regular bean. 如果使用Spring Framework ,则只需创建一个常规bean即可。 By default (or if you explicitly set scope="singleton" ) only one instance of the bean is created and that instance is returned every time the bean is used in a dependency or retrieved via getBean() . 默认情况下(或者如果显式设置scope="singleton" ),只创建一个bean实例,并在每次在依赖项中使用bean或通过getBean()检索时返回该实例。

You get the advantage of the single instance, without the coupling of the Singleton pattern. 您可以获得单个实例的优势,而无需耦合Singleton模式。

另一种方法是传递你需要的东西,而不是向对象询问事物。

don't accumulate responsibilites to a single configuration object since it will ends in a very big object that is both difficult to understand and fragile. 不要将责任累积到单个配置对象,因为它将以一个难以理解和脆弱的非常大的对象结束。

For example if you need another parameter to a particular class you change the Configuration object, then recompile all the classes that uses it. 例如,如果您需要特定类的其他参数,则更改Configuration对象,然后重新编译使用它的所有类。 This is somewhat problematic. 这有点问题。

Try refactoring your code to avoid a common, global and big Configuration object. 尝试重构代码以避免使用常见的全局和大型Configuration对象。 Pass only required parameters to client classes: 仅将必需参数传递给客户端类:

class Server {

    int port;

    Server(Configuration config) {
        this.port = config.getServerPort();
    } 

}

should be refactored to: 应该重构为:

 class Server {

    public Server(int port) {
       this.port = port;
    }
 }

a dependency injection framework will help a lot here, but it isn't stricly required. 依赖注入框架在这里会有很多帮助,但并不是非常严格要求。

You can accomplish the same behavior of singleton by using static methods. 您可以使用静态方法完成单例的相同行为。 Steve yegge explains it very well in this post. Steve yegge在这篇文章中解释得非常好。

Is a class that contains only static methods and fields possible? 是一个只包含静态方法和字段的类吗? I'm not sure of exactly what your situation is, but it might be worth looking into. 我不确定你的情况究竟是什么,但值得深入研究。

Maybe not very clean either, but you could maybe pass the information bits you want to have changed to the method that creates the singleton -- instead of using 也许也不是很干净,但你可以将你想要改变的信息位传递给创建单例的方法 - 而不是使用

public static Singleton getInstance() {
    if(singleton != null)
        createSingleton();
        return singleton;
    }
}

you could call createSingleton(Information info) directly on application startup (and in the setUp-Methods of the unit tests). 您可以直接在应用程序启动时调用createSingleton(Information info) (以及单元测试的setUp-Methods)。

Depends on what tooling/frameworks etc.. are being used. 取决于正在使用的工具/框架等。 With dependency injection/ioc tools one can often still get singleton performance/optimizations by having the di/ioc container use singleton behaviour for the class required - (such as a IConfigSettings interface) by only ever creating one instance of the class. 使用依赖注入/ ioc工具,通过让di / ioc容器对所需的类使用单例行为(例如IConfigSettings接口),只需创建一个类的实例,通常仍然可以获得单例性能/优化。 This could be still substituted out for testing 这仍然可以替代测试

Alternately one could use a factory to create the class and return the same instance each time you request it - but for testing it could return a stubbed/mocked version 或者,可以使用工厂创建类并在每次请求时返回相同的实例 - 但是为了测试它可以返回存根/模拟版本

Review possibility to make configuration as callback interface. 检查将配置作为回调接口的可能性。 So your configuration sensitive code will look: 所以你的配置敏感代码看起来像:

MyReuseCode.Configure(IConfiguration)

System-init code will look: System-init代码将显示:

Library.init(MyIConfigurationImpl)

You could use a dependency injection framework to ease the pain of passing in the configuration object. 您可以使用依赖项注入框架来减轻传递配置对象的痛苦。 A decent one is ninject which has the advantage of using code rather than xml. 一个像样的是ninject ,它具有使用代码而不是xml的优点。

Singletons are not evil but the design pattern is flawed. 单身人士并不邪恶,但设计模式存在缺陷。 I have a class that I only want to create a single instance of it during runtime but want to create multiple isolated instances during unit testing to ensure deterministic results. 我有一个类,我只想在运行时创建它的单个实例,但希望在单元测试期间创建多个隔离的实例,以确保确定性结果。

DI using Spring, etc, is a very good option but not the only option. DI使用Spring等是一个非常好的选择,但不是唯一的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM