美化的全局变量-变成一个美化的全局类。有人说打破面向对象设计。

给我一些场景,除了使用单例是有意义的良好的老记录器。


当前回答

在我寻求真相的过程中,我发现实际上很少有“可接受的”理由使用Singleton。

在互联网上反复出现的一个原因是“日志记录”类(你提到过)。在这种情况下,可以使用Singleton来代替类的单个实例,因为日志类通常需要被项目中的每个类反复使用,令人作呕。如果每个类都使用这个日志类,依赖注入就变得很麻烦。

日志记录是“可接受的”单例的一个特定示例,因为它不会影响代码的执行。禁用日志记录,代码执行保持不变。启用它,一样。Misko在《单例的根本原因》中这样说:“这里的信息单向流动:从应用程序流向记录器。即使记录器是全局状态,由于没有信息从记录器流入应用程序,记录器也是可以接受的。”

我相信还有其他合理的原因。Alex Miller在“我讨厌的模式”中谈到,服务定位器和客户端UI也可能是“可接受的”选择。

阅读更多在Singleton我爱你,但你让我失望。

其他回答

在我寻求真相的过程中,我发现实际上很少有“可接受的”理由使用Singleton。

在互联网上反复出现的一个原因是“日志记录”类(你提到过)。在这种情况下,可以使用Singleton来代替类的单个实例,因为日志类通常需要被项目中的每个类反复使用,令人作呕。如果每个类都使用这个日志类,依赖注入就变得很麻烦。

日志记录是“可接受的”单例的一个特定示例,因为它不会影响代码的执行。禁用日志记录,代码执行保持不变。启用它,一样。Misko在《单例的根本原因》中这样说:“这里的信息单向流动:从应用程序流向记录器。即使记录器是全局状态,由于没有信息从记录器流入应用程序,记录器也是可以接受的。”

我相信还有其他合理的原因。Alex Miller在“我讨厌的模式”中谈到,服务定位器和客户端UI也可能是“可接受的”选择。

阅读更多在Singleton我爱你,但你让我失望。

共享资源。特别是在PHP中,数据库类、模板类和全局变量库类。所有这些都必须由代码中使用的所有模块/类共享。

这是一个真正的对象使用——>模板类包含正在构建的页面模板,它被添加到页面输出的模块塑造、添加、更改。它必须保持为单个实例,这样才能实现这一点,数据库也是如此。使用共享数据库单例,所有模块的类都可以访问查询,并且无需重新运行查询。

全局变量仓库单例为您提供了一个全局的、可靠的、易于使用的变量仓库。它极大地整理了你的代码。想象一下,所有配置值都在一个单例数组中,如下所示:

美元gb - > problem[’hostname’]

或者将所有的语言值放在一个数组中,比如:

gb - >朗(“ENTER_USER”)

在运行页面代码的最后,你会得到,比如说,一个现在成熟的:

美元的模板

Singleton,一个$gb的Singleton,其中有lang数组用于替换,所有输出都已加载并准备就绪。您只需将它们替换为现在在成熟模板对象的页面值中呈现的键,然后将其提供给用户。

这样做的最大好处是你可以对任何东西做任何你喜欢的后期处理。您可以将所有语言值输送到谷歌translate或其他翻译服务,并将它们返回,并将它们替换到它们的位置,例如,已翻译。或者,您可以根据需要替换页面结构或内容字符串。

I use it for an object encapsulating command-line parameters when dealing with pluggable modules. The main program doesn't know what the command-line parameters are for modules that get loaded (and doesn't always even know what modules are being loaded). e.g., main loads A, which doesn't need any parameters itself (so why it should take an extra pointer / reference / whatever, I'm not sure - looks like pollution), then loads modules X, Y, and Z. Two of these, say X and Z, need (or accept) parameters, so they call back to the command-line singleton to tell it what parameters to accept, and the at runtime they call back to find out if the user actually has specified any of them.

在很多方面,处理CGI参数的单例方式与你每次查询只使用一个进程类似(其他mod_*方法不这样做,所以这很糟糕——因此这个参数说你不应该在mod_cgi世界中使用单例,以防你移植到mod_perl或其他世界)。

首先,让我们区分一下单对象和单对象。后者是前者的许多可能实现之一。而且单对象的问题与单例的问题是不同的。单对象本身并不坏,有时是做事情的唯一方法。简而言之:

单对象-我只需要程序中对象的一个实例 Singleton -创建一个带有静态字段的类。添加一个返回此字段的静态方法。在第一次调用时惰性地实例化一个字段。总是返回相同的对象。

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton instance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

如您所见,规范形式的“单例”模式对测试不是很友好。不过,这个问题很容易解决:只要让Singleton实现一个接口。让我们称它为“可测试单例”:)

public class Singleton implements ISingleton {
    private static Singleton instance;

    private Singleton() {}

    public static ISingleton instance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

现在我们可以模拟Singleton了,因为我们通过接口来使用它。其中一项索赔消失了。让我们看看是否可以去掉另一个声明-共享全局状态。

如果我们剥离单例模式,它的核心是惰性初始化:

public static ISingleton instance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

这就是它存在的全部原因。这就是单对象模式。我们把它拿走,放到工厂方法中,例如:

public class SingletonFactory {
    private static ISingleton instance;

    // Knock-knock. Single Object here
    public static ISingleton simpleSingleton() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

与我们的可测试单例有什么不同?没有,因为这是单对象模式的本质——不管你是把它实现为单例、工厂方法还是服务定位器。你仍然有一些共享的全局状态。如果从多个线程访问它,这可能会成为一个问题。您将不得不使simpleSingleton()同步并处理所有多线程问题。

再说一遍:无论你选择什么方法,你都必须付出单一对象的代价。使用依赖注入容器只是将复杂性转移到框架,它将不得不处理单对象的固有问题。

回顾:

Most of people who mention Singleton mean Single Object One of the popular ways to implement it is the Singleton pattern It has its flaws that can be mitigated However, the most of Singleton's complexity roots in Single Object's complexity Regardless of how you instantiate your Single Object, it's still there, be it a Service Locator, a Factory Method or something else You can shift the complexity to a DI container which is (hopefully) well-tested Sometimes using the DI container is cumbersome - imagine injecting a LOGGER to every class

也许是一个带有代码的示例。

在这里,ConcreteRegistry是一个纸牌游戏中的单例,它允许行为沿着包树向上访问游戏的少数核心接口(即模型、视图、控制器、环境等的外观):

http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html

Ed.