Set*_*ori 421 singleton design-patterns
荣耀的全球变量 - 成为一个荣耀的全球阶级.有人说打破面向对象的设计.
给我一些场景,除了好的旧记录器,使用单例是有意义的.
Cod*_*nts 347
在我追求真相的过程中,我发现使用Singleton实际上很少有"可接受"的理由.
在互联网上一次又一次地出现的一个原因是"日志记录"类(你提到过).在这种情况下,可以使用Singleton而不是类的单个实例,因为项目中的每个类通常需要反复使用日志记录类.如果每个类都使用此日志记录类,则依赖项注入会变得很麻烦.
日志记录是"可接受的"Singleton的一个特定示例,因为它不会影响代码的执行.禁用日志记录,代码执行保持不变.启用它,同样相同.Misko在单根的根本原因中将其置于以下方式,"这里的信息以一种方式流动:从您的应用程序进入记录器.即使记录器是全局状态,由于没有信息从记录器流入您的应用程序,因此记录器是可接受的."
我相信还有其他正当理由.Alex Miller在" 模式我讨厌 "中讨论了服务定位器和客户端UI也可能是"可接受的"选择.
met*_*tao 120
Singleton候选人必须满足三个要求:
如果您提出的Singleton只有一个或两个这样的要求,重新设计几乎总是正确的选择.
例如,不太可能从多个位置("打印"菜单)调用打印机假脱机程序,因此您可以使用互斥锁来解决并发访问问题.
简单的记录器是可能有效的Singleton的最明显的例子,但是这可以随着更复杂的记录方案而改变.
Pau*_*kin 43
读取应该只在启动时读取并将它们封装在Singleton中的配置文件.
Vin*_*nie 35
您需要管理共享资源时使用单例.例如打印机假脱机程序.您的应用程序应该只有一个假脱机程序实例,以避免对同一资源的请求冲突.
或者数据库连接或文件管理器等.
Mar*_*ett 23
只读单例存储一些全局状态(用户语言,帮助文件路径,应用程序路径)是合理的.小心使用单例来控制业务逻辑 - 单个几乎总是最终成为多个
Fed*_*oni 16
管理数据库的连接(或连接池).
我还会用它来检索和存储外部配置文件的信息.
Dav*_*kle 10
使用单例的一种方法是覆盖必须有一个"代理"控制对资源的访问的实例.单身人士在记录器方面表现优异,因为他们可以代理访问一个文件,这个文件只能写入.对于像日志记录这样的东西,它们提供了一种将写入抽象为日志文件的方法 - 你可以将缓存机制包装到你的单例等等......
还要考虑一种情况,你有一个应用程序有许多windows/threads/etc,但需要单点通信.我曾经用一个来控制我希望我的应用程序启动的作业.单身人员负责序列化工作并将其状态显示给感兴趣的程序的任何其他部分.在这种情况下,你可以看一个单例就像在你的应用程序中运行的"服务器"类...... HTH
Ada*_*ess 10
在管理对整个应用程序共享的资源的访问时,应使用单例,并且可能具有同一类的多个实例是破坏性的.确保对共享资源线程安全的访问是这种模式至关重要的一个非常好的例子.
使用单身人士时,你应该确保你不会意外地隐藏依赖关系.理想情况下,单个应用程序(如应用程序中的大多数静态变量)在执行应用程序的初始化代码期间设置(静态void Main()用于C#可执行文件,static void main()用于java可执行文件)然后传入所有其他需要实例化的类.这有助于您保持可测试性.
单例的一个实际例子可以在Test :: Builder中找到,这个类几乎支持每个现代Perl测试模块.Test :: Builder singleton存储和代理测试过程的状态和历史(历史测试结果,计算运行测试的数量)以及测试输出的去向.这些都是协调由不同作者编写的多个测试模块在一个测试脚本中协同工作所必需的.
Test :: Builder的单身人士的历史是教育性的.调用new()总是给你相同的对象.首先,所有数据都存储为类变量,对象本身没有任何内容.这一直有效,直到我想用自己测试Test :: Builder.然后我需要两个Test :: Builder对象,一个设置为虚拟对象,捕获并测试其行为和输出,一个是真正的测试对象.此时,Test :: Builder被重构为一个真实的对象.单例对象存储为类数据,并new()始终返回它.  create()添加了一个新对象并启用测试.
目前,用户希望在自己的模块中更改Test :: Builder的某些行为,但是让其他人保持独立,而测试历史在所有测试模块中保持共同.现在发生的事情是单片Test :: Builder对象被分解成更小的片段(历史,输出,格式......),其中一个Test :: Builder实例将它们收集在一起.现在,Test :: Builder不再是一个单身人士.它的组成部分,如历史,可以.这将单身人士的灵活必要性推向了一个层次.它为用户提供了更多的混合和匹配件的灵活性.较小的单例对象现在可以只存储数据,其包含的对象决定如何使用它.它甚至允许非Test :: Builder类通过使用Test :: Builder历史记录和输出单例来进行.
似乎是在数据协调和行为灵活性之间存在推动和拉动,这可以通过将单例放在仅具有最小行为的共享数据来减轻,以确保数据完整性.
小智 5
共享资源。特别是在PHP中,数据库类、模板类和全局变量库类。所有这些都必须由整个代码中使用的所有模块/类共享。
这是真正的对象用法 -> 模板类包含正在构建的页面模板,并且它由添加到页面输出的模块来塑造、添加和更改。它必须保留为单个实例才能发生这种情况,数据库也是如此。通过共享数据库单例,所有模块的类都可以访问查询并获取它们,而无需重新运行它们。
全局变量库单例为您提供了一个全局、可靠且易于使用的变量库。它极大地整理了你的代码。想象一下,将所有配置值放在一个单例数组中,如下所示:
$gb->config['hostname']  
或者将所有语言值放在一个数组中,例如:
$gb->lang['ENTER_USER']
在运行页面代码结束时,您会得到一个现在成熟的:
$template 
Singleton,一个$gb具有用于替换的 lang 数组的单例,并且所有输出均已加载并准备就绪。您只需将它们替换为现在存在于成熟模板对象的页面值中的键,然后将其提供给用户。
这样做的最大优点是您可以对任何东西进行任何您喜欢的后期处理。您可以将所有语言值通过管道传输到谷歌翻译或其他翻译服务并将它们取回,然后将它们替换到翻译后的位置。或者,您可以根据需要替换页面结构或内容字符串。
首先,让我们区分Single Object和Singleton。后者是前者的许多可能实现方式之一。而且 Single Object 的问题与 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;
    }
}
和我们的Testable Singleton有什么区别?没有,因为这是单一对象模式的本质 - 无论您将其实现为单例、工厂方法还是服务定位器,都没有关系。您仍然拥有一些共享的全局状态。如果从多个线程访问它,这可能会成为一个问题。你必须做simpleSingleton()同步并处理所有多线程问题。
再一次:无论您选择哪种方法,您都必须支付单个对象的价格。使用依赖注入容器只是将复杂性转移到框架上,框架必须处理单个对象的固有问题。
回顾:
当您想要确保一个类有一个实例,并且该实例将具有对其的全局访问点时,可以使用单例设计模式。
假设您有一个应用程序需要数据库来处理 CRUD 操作。理想情况下,您可以使用与数据库相同的连接对象来访问数据库并执行 CRUD 操作。
因此,为了确保数据库类拥有一个对象,并且在整个应用程序中使用同一个对象,我们实现了单例设计模式。
确保您的构造函数是私有的,并且提供静态方法来提供对单例类的单个对象的访问