0

来自 .NET/C# 背景并且对 PRISM 有深入的了解,我真的很喜欢在CompositionContainer需要时只获取一个类的这个实例的想法。

由于通过ServiceLocatorthis 实例也可以全局访问,这几乎可以概括为单例模式。

现在,我当前的项目是 c++,我正在决定如何管理程序的插件(外部 dll 加载和类似的东西)。

在 C# 中,我将创建一个 PluginService,将其导出为共享并通过该实例引导所有内容(成员基本上只相当于一个列表,包含插件和一堆方法)。在 c++ 中,显然我没有 aCompositionContainer或 a ServiceLocator

我可能会实现这个的基本版本,但无论我想象什么都涉及使用单例或全局变量。不过,对此的普遍担忧似乎是:永远不要做全球性的事情,更不要做单身人士。

我是什么做的?(我也感兴趣的是:微软在这里给我们提供了一个关于如何编码的坏例子,或者这是一个单例是正确选择的实际案例?)

4

2 回答 2

6

在全局变量和单例是“好”还是“坏”方面,C# 和 C++ 之间确实没有区别。

您概述的解决方案在 C# 和 C++ 中同样糟糕(或良好)。

你似乎发现的只是不同的人有不同的看法。一些 C# 开发人员喜欢使用单例来完成类似的事情。一些 C++ 程序员也有同样的感觉。

一些 C++ 程序员认为单例是一个糟糕的主意,而且……一些 C# 程序员也有同样的感觉。:)

微软给出了许多关于如何编码的坏例子。永远不要仅仅因为它在盒子上写着微软就接受他们的示例代码作为“良好实践”。重要的是代码,而不是其背后的名称。

现在,我对单身人士的主要不满并不是他们的全球方面。

像大多数人一样,我通常不喜欢和不信任全局变量,但我不会说永远不应该使用它们。在某些情况下,使某些东西可以全局访问会更方便。它们并不常见(我认为大多数人仍然过度使用全局变量),但它们存在。

但是单例的真正问题是它们对您的代码施加了不必要且通常有害的约束:它们阻止您创建对象的多个实例,就好像您在编写类时知道如何更好地使用它实际用户会。

当您编写一个类时,例如,PluginService正如您在评论中提到的那样,您当然对您计划如何使用它有所了解。你可能认为“它的一个实例应该是全局可访问的(这是有争议的,因为许多类不应该访问插件服务,但我们假设我们现在确实希望它是全局的)。你可能认为“我不能想象一下为什么我想要两个实例”。

但问题是当你采取这个假设并积极阻止创建两个实例时。

如果从现在开始的两个月后,您发现需要创建两个 PluginServices 怎么办?如果您在编写类时采用了简单的方法,并且没有在其中构建不必要的约束,那么您现在可以采用简单的方法,只需创建两个实例即可。

但是,如果您采取了编写额外代码以防止创建多个实例的困难路径,那么您现在必须再次采取困难路径:现在您必须返回并更改您的类。

除非你有理由,否则不要在你的代码中设置限制:如果它使你的工作更容易,那就继续做吧。如果它可以防止对课程的有害滥用,那就去做吧。

但在单例的情况下,这两者都没有:您为自己创造额外的工作,以防止可能完全合法的使用。

您可能有兴趣阅读我为回答单身问题而写的这篇博文。

但要回答如何处理您的具体情况的具体问题,我会推荐以下两种方法之一:

  • “纯粹”的方法是创建一个ServiceLocator全球性的。将其传递给需要查找服务的人。根据我的经验,您可能会发现这比听起来要容易得多。您往往会发现在许多不同的地方实际上并不需要它,因为您认为它会是。它给你一个动力去解耦代码,最小化依赖,确保只有那些真正需要ServiceLocator 的人才能访问它。这很健康。
  • 或者有一种务实的方法:创建ServiceLocator. 任何需要它的人都可以使用它,而且毫无疑问如何找到它——毕竟它是全球性的。但不要让它成为单例。让创建其他实例成为可能。如果您永远不需要创建另一个实例,那么就不要这样做。但这让大门敞开,因此如果您最终需要另一个实例,您可以创建它。

在许多情况下,您最终需要一个您认为只需要一个实例的类的多个实例。围绕某些硬件的配置/设置对象、记录器或包装器都是人们经常所说的“这显然应该是一个单例,拥有多个实例是没有意义的”,并且在每种情况下,它们都是错误的. 在很多情况下,您需要此类类的多个实例。

但最普遍适用的场景很简单:测试。

您要确保您的 ServiceLocator正常工作。所以你想测试它。

如果是单例,那真的很难做到。一个好的测试应该在原始、隔离的环境中运行,不受之前测试的影响。但是一个单例在应用程序的持续时间内存在,所以如果你有多个 ServiceLocator 测试,它们都会在同一个“脏”实例上运行,所以每个测试都可能影响下一个测试看到的状态。

相反,每个测试都应该创建一个新的、干净的 ServiceLocator,这样它们就可以准确地控制它所处的状态。为此,您需要能够创建该类的实例。

所以不要让它成为单例。:)

于 2012-08-24T11:19:04.900 回答
1

在合适的情况下,单身人士绝对没有错。我对此表示怀疑CompositionContainer(但我不确定我是否理解它实际上应该做什么),但 ServiceLocator在任何设计良好的应用程序中通常都是单例的。拥有两个或更多ServiceLocator 将导致程序无法正常运行(因为服务将在其中一个中注册,而您将在另一个中查找它);以编程方式执行这一点是积极的,至少如果您喜欢健壮的编程。另外,在C++中,单例习语用来控制初始化的顺序;除非你做 ServiceLocator一个单例,否则你不能在任何具有静态生命周期的对象的构造函数中使用它。

While there is a small group of very vocal anti-singleton fanatics, within the larger C++ community, you'll find that the consensus favors singletons, in certain very restricted cases. They're easily abused (but then, so are templates, dynamic allocation and polymorphism), but they do solve one particular problem very nicely, and it would be silly to forgo them for some arbitrary dogmatic reason when they're the best solution for the problem.

于 2012-08-24T12:44:21.023 回答