2

我遇到了这个页面,它对单身人士有一个非常好的、全面的概述。

代替常见的“单例是一个具有私有构造函数且只有一个全局实例的类”,它描述了单例如下:

准确定义我们所说的“单例”是很重要的。

就本论点而言,单例是任何可变状态,无需从堆栈开始即可到达(即从静态或全局变量可到达)。

通常,单例是作者期望只有一个实例的类。但是,就我们的目的而言,任何可全局访问的对象都很重要。

例子:

  • 一组操纵某些共享可变状态的函数(或静态方法)构成一个单例。
  • 如果单例 A 提供对可变对象 B 的引用,则 B 也是单例。
  • 这意味着单例集合的每个可变成员本身就是一个单例。
  • 即使全局可访问,传递不可变对象也不是单例。它是一个常数。
  • 假设代码是不可变的,不访问任何单例的独立函数本身不是单例。

...

那么 open() 或标准输出呢?

这些是单身人士的一些最糟糕的例子!
...

从本质上讲,这意味着 , malloc,newshared_ptr任何你的语言用来访问堆内存的东西——所有这些都使用单例!

然而,没有人说我们需要因此避免堆分配。内存分配似乎到处都被忽视了!即使在我引用的页面上,他们也提到了open()stdout日志记录,但他们从未提到堆内存分配——这显然比记录器更“危险”,因为它不是单向街道。

所以我的问题是,内存分配是规则的一个例外(为什么?),还是例的一个坏例子?

我如何确定单身人士的新用途是否属于同一“例外”类别?

(出于显而易见的原因,标记为与语言无关,但也标记为 C++,因为我认为它与 C++ 特别相关,因为它允许用户修改行为new并引入更多全局状态。)

4

1 回答 1

1

根据定义,您的程序只与一个外部世界交互。所以没有人会争辩说这不是单例的例子!

但是从软件设计的角度来看,我会说好的/不好的实际上只是一个“这会给我带来麻烦吗?”的问题。和“我能做些什么吗?”。

对于输出之类的东西,两者的答案都是“是”。在复杂的程序中,通过将输出封装在非单例对象中可以获得相当大的好处(测试、依赖注入等)。对于像系统内存这样的东西,不是那么多。

您可以寻求抽象出一些固有的耦合(实际上,操作系统、语言运行时以及自定义分配器之类的东西都在某种程度上在内存的情况下做到了这一点)。将所有内存分配封装在对象后面也可能会有所帮助,以允许测试复杂的应用程序对内存不足条件的响应。但是你仍然不能完全消除全局耦合。

于 2013-03-28T19:08:25.463 回答