替代单例模式的方案

15

这与以下相关:单例模式有什么不好

你能给我一些使用其他技术避免使用单例模式的示例吗? 我需要在C ++中使用,因此您可以使用具有C ++特定技术的示例。

更明确地说:如何在没有单例模式的情况下实现文件管理器、资源管理器、日志管理器等。


3
你明白它们为什么不好吗? - GManNickG
2
单例模式并不是坏的。像文件管理器和日志管理器这样的东西就是单例模式所用的。将它们用于它们不应用的事情,会让每个人都认为它们是不好的。 - user684934
2
“从上面参数化”通常是消除单例模式时使用的模式。 - CB Bailey
2
@bdares:对于文件或日志管理器而言,一个全局访问点通常是一件好事。根据我的经验,不能有第二个文件或日志管理器通常不是问题。所有的概括都是错误的,但“单例模式是不好的”是一个相当好的概括。在我看来。 - CB Bailey
1
@MerlynMorganGraham:它们并不是完全相同的东西。据我所知,DI 是关于消除函数或类对特定具体类型的依赖,而 PfA 则简单得多,它只是关于删除函数或类对如何访问对象的知识,而是接收一个需要作为参数的对象的引用。我认为这篇文章写得很好。各有所好。 - CB Bailey
显示剩余5条评论
3个回答

35
简而言之,创建一个文件管理器类的单个实例,并根据需要在应用程序中传递它。通常情况下,您有某种控制器对象来创建应用程序中的其他重要对象。这可能是实例化文件管理器的对象,然后将其传递给创建需要文件管理器的其他对象。
如果您使用单例模式是因为某个类必须只有一个实例,那通常是可以的。但是,如果您使用单例模式是因为它是全局可访问的对象,可以避免考虑其他对象如何相互交流以及每个对象负责什么,那么就会遇到问题。
文件管理器是一个很好的例子。起初似乎文件管理器对象只应该有零个或一个实例。但这是必要的吗?难道一台机器上不能同时有两个文件系统吗?

9
强调“Only 1”通常是由于目光短浅而非其他原因,给你加1个赞。 - Matthieu M.

7
你如何在没有单例模式的情况下实现文件管理器、资源管理器、日志管理器等?通过不将它们作为单例,而是将它们作为参数和引用传递给调用树和对象网络。一般来说,如果你只需要n个实例,那么就创建n个实例。或者说,如果两个良好设计的类的实例不会冲突而违反类的契约,则不要将其作为单例。

一个很好的通用规则。更进一步,n==1并不意味着需要一个单例。 - Caleb
1
@Caleb:当然。作为后续,我会再添加一条规则。 - Sebastian Mach

3
你能给我一些使用其他技术避免使用单例模式的示例吗?
在高级代码中,直接创建实例并将其传递。您应该在尽可能高的级别上执行此操作,但仍然是有意义的。
在低级代码中,将对现有实例的引用作为参数接受。如果可以避免使用工厂而不影响设计,则不要接受工厂,并且绝对不要在与该类的逻辑无关的事物上调用构造函数/ new 。
如果遵循这两个规则,则会隐式地管理创建的实例数,并且不会通过强制使用单例设计(通常是短视的)将自己限制在一个角落里。
你如何实现文件管理器、资源管理器、日志管理器等,而不使用单例模式?
我不会使用单例模式,而是创建可以实例化的类,并让应用程序本身决定创建多少个实例以及如何创建它们。
同时,我也不会让我的应用程序的低级部分做任何决定。仅仅因为我要写入日志并不意味着我必须知道它应该存储在哪里,我正在写入日志层次结构的哪个级别,应该应用什么过滤器等等。
我会让我的代码的高级部分决定这些事情。这样,如果我改变主意,我可以放弃先前的决定,重新创建一些顶层代码,并且不触及任何写入日志的代码(我的应用程序的大部分)。

我离开了键盘,完成了这个任务,然后发现我已经晚了。这基本上是和Caleb说的一样。不管怎样,我还是会留下来的 :) - Merlyn Morgan-Graham
当你处理一个基本上是单例的概念时会发生什么?你会有一堆浮动的对象,它们都只是引用同一个内部数据吗? - Nicol Bolas
1
@Nicol:不,你只需要创建一个实例并传递它。我并不是说要创建不必要的实例。然而,一旦采用了合适的抽象层次,我很难想到哪些概念基本上是单例的。常见的例子如各种管理器和打印池,其实并不是所谓的Singletons。仅仅因为在应用程序中你想要只有一个实例,并不意味着只有一个实例是唯一有意义的选择。 - Merlyn Morgan-Graham
@Merlyn:如果只有一个打印池是有意义的,那么允许创建多个的API就是一个糟糕的设计。如果每个实例都只是在与相同的内容交互,那么允许创建多个的抽象又有什么好处呢?零、一或无限规则中之所以包含“一”,是有其原因的。 - Nicol Bolas
1
@Nicol:我不同意,但我不应该走得这么远。我忘记了这是一场圣战 :) 我现在退出。 - Merlyn Morgan-Graham
2
@Nicol:那就只做一个呗。你又不是经常不小心做出来打印机缓冲区,而且你凭什么说我不需要两个? - GManNickG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接