11

可能的重复:
关于设计模式:何时使用单例?

这个问题不是关于单例是否总体上“被认为是有害的”。根据您的经验,我只想知道单例在哪些特定情况下似乎可以很好地工作。

编辑: 请,如果您想讨论单身人士的适当性和/或邪恶性有一个已经存在的问题137975、11831

哎呀!我刚刚发现我的问题已经在这里提出了:关于设计模式:何时使用单例?

4

12 回答 12

8

我们基本上将它们用于两件事:日志记录和配置。两者都假设应用程序有一个中央配置和一个中央日志文件,这并不总是有效的,但在我们的大多数代码中都是有效的。我们有时也会将它们用于某些工厂类或缓存类,以确保我们不会复制关键元数据。

于 2010-01-17T12:55:24.383 回答
5

扩展我的评论...

这个问题措辞不佳,单例似乎在许多情况下都能很好地工作。应该是“在哪些特定情况下单例不暴露其负面属性?” 简而言之,“全局变量什么时候好”?

  1. 全局变量是全局变量。

    只要你使用

    void f() { X* x = X::getInstance(); ... }

    而不是void f(X*),您订购的意大利面条菜已被接受。

  2. 单身人士激增,并且喜欢相互依赖。 SessionManager使用EventManager哪个使用LogManager。有人希望日志文件提及当前用户的名称。LogManager维护者补充说SessionManager::getInstance()->getUser()->getName();,一切都很顺利,直到同样使用 的,LoginManager想要LogManager记录登录失败。

  3. 单例会抑制可测试性。

    单实例属性仅在生产代码中是半有用的。您可能根本无法测试该void f()功能,并且可能仅针对快乐路径进行(很少)测试。

你可以猜到,我的回答是什么时候全局变量好?是“从不”。你的是什么

于 2010-01-17T14:29:30.187 回答
2
  • 当您的域指定只存在一个您正在建模的事物的唯一实例时

我仍然认为应该避免单例(至少在 Java 中)。

有两件不同的事情需要考虑:执行单例模式的概念机制

单例的概念有很多用途,日志记录,配置,更不用说当你正在工作的域实际上有一些东西时,它们只有一个实例并且你希望对其进行建模。即公司只有一个费用处理办公室,将费用表格发送到无效办公室是错误的,该办公室实际上是一个单身人士。单例的概念有许多合法用途。

但是,它通常是导致问题的机制。在 Java 中,我们强制不能通过声明构造函数来构造对象private,这样做的问题是我们还必须通过具体类提供对实例的全局访问点。这将应用程序中的所有内容与具体类耦合在一起,该类不能在运行时更改,也不能在单元测试中模拟。正是这种机制被认为是邪恶的——尤其是在可测试性方面。

如果 Singletons 的概念可以从糟糕的机制中分离出来,它们就不会那么邪恶了。我能想到的一个例子是@SingletonGuice 中可用的范围。在 Guice 的上下文中,它保证一个实例,但它并没有通过邪恶的私有构造函数/全局访问点机制来实现这一点。

于 2010-01-17T16:16:07.523 回答
2

生成随机数序列 - 随机生成器应该是唯一的,而不是为每次使用而实例化。有人可能希望将其实现为线程级单例;但是,在这种情况下,整个过程的单例仍然是合适的。

于 2010-01-17T16:41:52.640 回答
1

系统连接了一个设备/硬件,并且需要一个中央控制点才能正确使用它。

于 2010-01-17T10:15:23.673 回答
1
  • 记录。

  • 查找本地化字符串资源,例如Strings.get("CONFIRM_DELETE").

这两件事都不是应该在对象的公共接口中公开的细节,因此在这里使用单例是有意义的。

于 2010-01-17T13:25:45.463 回答
0

在我正在进行的当前项目中,我非常努力地摆脱了单身人士。它们有气味,但有时很难避免。

我的情况是我有一个 API,它构造了用于处理管理功能(如安全、配置等)的单例对象。该 API 使用 EntityFramework 并且还引入了插件(使用 MEF)。因为这些类的构造并不总是由我的代码执行(尤其是对于 EF 实体),所以并不总是可以优雅地将这些类注入到 biz 对象中。所以我使用了单例,它可以在项目范围内的任何地方访问。

于 2010-01-17T10:17:31.480 回答
0

主服务器从客户端接收请求,并将这些请求传递给从属进程。从属进程可以使用单例与主服务器通信。

于 2010-01-17T13:10:22.737 回答
0

我尽量不依赖 Singleton,但是我更喜欢解耦而不是使用 Singleton。因此,我经常将 Singleton 与 Prototype 模式结合使用,它允许在库加载时注册 Prototypes(全局对象构造)。

我正在编写一个由许多库组成的服务器。有许多“通用”库,然后每个服务一个库。“主”库的任务是查看收到的消息并根据密钥调用正确的服务......这使用一个简单的std::map.

对地图使用 Singleton 可以让我拥有完全解耦的代码。没有库依赖于我的服务库,我的服务库之外没有任何代码行负责注册其服务。事实上,我可以通过在编译时更改我的“链接”命令来决定嵌入哪些服务:如果我不与库链接,则它的服务不会被嵌入。

我真的觉得它在那里很有用...对于配置等我更喜欢使用 MonoPattern:即所有实例共享相同数据的普通类(因此包装了一个真正的单例)。使迁移更容易,以防万一,因为客户不知道他们正在使用 Singleton 卧底。

于 2010-01-17T13:11:30.347 回答
0

除了日志记录(正如大多数其他人已经提到的那样),我还使用单例来实现控制反转 (IoC) 容器。依赖关系在应用程序启动时注册一次,并且可以在应用程序期间的任何时间点使用单例方法解决依赖关系。

于 2010-01-17T13:34:30.497 回答
-1

它们适用于您希望视为独特资源的项目。

作为 Web 系统中的示例,您可能希望为每个提供服务的页面仅使用单个数据库连接 - 在这种情况下,使用单例模式是有意义的。(尽管您必须在知道数据库访问对象是单例的情况下进行编码,这不太理想,但如果清楚地记录在案等情况下是可以接受的)

于 2010-01-17T10:18:30.010 回答
-1

当您的程序的一部分需要一个实现特定接口(多态性)的对象,但您永远不需要该对象的单个实例。否则静态方法就可以了。

于 2010-01-17T12:58:37.777 回答