I was confused when I first started to see anti-singleton commentary. I have used the singleton pattern in some recent projects, and it was working out beautifully. So much so, in fact, that I have used it many, many times.
当我第一次看到反单身评论时,我很困惑。我在最近的一些项目中使用了单例模式,并且它运行得很漂亮。事实上,我已经使用了很多次。
Now, after running into some problems, reading this SO question, and especially this blog post, I understand the evil that I have brought into the world.
现在,在遇到一些问题之后,阅读这个SO问题,特别是这篇博文,我理解了我带给世界的邪恶。
So: How do I go about removing singletons from existing code?
那么:我如何从现有代码中删除单例?
For example:
In a retail store management program, I used the MVC pattern. My Model objects describe the store, the user interface is the View, and I have a set of Controllers that act as liason between the two. Great. Except that I made the Store into a singleton (since the application only ever manages one store at a time), and I also made most of my Controller classes into singletons (one mainWindow, one menuBar, one productEditor...). Now, most of my Controller classes get access the other singletons like this:
例如:在零售店管理程序中,我使用了MVC模式。我的Model对象描述了商店,用户界面是View,我有一组控制器,它们充当两者之间的联络。大。除了我把Store变成一个单例(因为应用程序一次只管理一个商店),我还把我的大部分Controller类都变成了单例(一个mainWindow,一个menuBar,一个productEditor ......)。现在,我的大多数Controller类都可以像这样访问其他单例:
Store managedStore = Store::getInstance();
managedStore.doSomething();
managedStore.doSomethingElse();
//etc.
Should I instead:
我应该改为:
- Create one instance of each object and pass references to every object that needs access to them?
- Use globals?
- Something else?
创建每个对象的一个实例,并将引用传递给需要访问它们的每个对象?
Globals would still be bad, but at least they wouldn't be pretending.
Globals仍然会很糟糕,但至少他们不会假装。
I see #1 quickly leading to horribly inflated constructor calls:
我看到#1迅速导致可怕的膨胀构造函数调用:
someVar = SomeControllerClass(managedStore, menuBar, editor, sasquatch, ...)
Has anyone else been through this yet? What is the OO way to give many individual classes acces to a common variable without it being a global or a singleton?
还有其他人经历过这个吗?如果不是全局变量或单个变量,那么为多个单独的类访问公共变量的OO方法是什么?
8 个解决方案
#1
Dependency Injection is your friend.
依赖注入是你的朋友。
Take a look at these posts on the excellent Google Testing Blog:
在优秀的Google测试博客上查看这些帖子:
- Singletons are pathologic liars (but you probably already understand this if you are asking this question)
- A talk on Dependency Injection
- Guide to Writing Testable Code
单身人士是病态的骗子(但如果你问这个问题,你可能已经理解了这一点)
关于依赖注入的讨论
编写可测试代码的指南
Hopefully someone has made a DI framework/container for the C++ world? Looks like Google has released a C++ Testing Framework and a C++ Mocking Framework, which might help you out.
希望有人为C ++世界制作了DI框架/容器?看起来谷歌发布了一个C ++测试框架和一个C ++模拟框架,可能会帮助你。
#2
It's not the Singleton-ness that is the problem. It's fine to have an object that there will only ever be one instance of. The problem is the global access. Your classes that use Store should receive a Store instance in the constructor (or have a Store property / data member that can be set) and they can all receive the same instance. Store can even keep logic within it to ensure that only one instance is ever created.
这不是单身人士的问题。拥有一个只有一个实例的对象,这很好。问题是全球访问。您使用Store的类应该在构造函数中接收Store实例(或者具有可以设置的Store属性/数据成员),并且它们都可以接收相同的实例。 Store甚至可以在其中保留逻辑,以确保只创建一个实例。
#3
My way to avoid singletons derives from the idea that "application global" doesn't mean "VM global" (i.e. static
). Therefore I introduce a ApplicationContext
class which holds much former static
singleton information that should be application global, like the configuration store. This context is passed into all structures. If you use any IOC container or service manager, you can use this to get access to the context.
我避免单身人士的方法源于“应用程序全局”并不意味着“虚拟机全局”(即静态)的观点。因此,我介绍了一个ApplicationContext类,它包含许多以前应该是应用程序全局的静态单例信息,就像配置存储一样。此上下文将传递到所有结构中。如果您使用任何IOC容器或服务管理器,则可以使用它来访问上下文。
#4
There's nothing wrong with using a global or a singleton in your program. Don't let anyone get dogmatic on you about that kind of crap. Rules and patterns are nice rules of thumb. But in the end it's your project and you should make your own judgments about how to handle situations involving global data.
在程序中使用全局或单例没有任何问题。不要让任何人对你说这种废话。规则和模式是很好的经验法则。但最终这是你的项目,你应该对如何处理涉及全局数据的情况做出自己的判断。
Unrestrained use of globals is bad news. But as long as you are diligent, they aren't going to kill your project. Some objects in a system deserve to be singleton. The standard input and outputs. Your log system. In a game, your graphics, sound, and input subsystems, as well as the database of game entities. In a GUI, your window and major panel components. Your configuration data, your plugin manager, your web server data. All these things are more or less inherently global to your application. I think your Store class would pass for it as well.
无限制地使用全局变量是个坏消息。但只要你勤奋,他们就不会杀了你的项目。系统中的某些对象应该是单例。标准输入和输出。你的日志系统。在游戏中,您的图形,声音和输入子系统,以及游戏实体的数据库。在GUI中,您的窗口和主要面板组件。您的配置数据,插件管理器,Web服务器数据。所有这些事情或多或少都与您的应用程序具有全局性。我认为你的Store类也会传递它。
It's clear what the cost of using globals is. Any part of your application could be modifying it. Tracking down bugs is hard when every line of code is a suspect in the investigation.
很清楚使用全局变量的成本是多少。您的应用程序的任何部分都可能正在修改它。当每行代码都是调查中的嫌疑人时,追踪错误很难。
But what about the cost of NOT using globals? Like everything else in programming, it's a trade off. If you avoid using globals, you end up having to pass those stateful objects as function parameters. Alternatively, you can pass them to a constructor and save them as a member variable. When you have multiple such objects, the situation worsens. You are now threading your state. In some cases, this isn't a problem. If you know only two or three functions need to handle that stateful Store object, it's the better solution.
但是不使用全局变量的成本呢?就像编程中的其他一切一样,这是一种权衡。如果避免使用全局变量,则最终必须将这些有状态对象作为函数参数传递。或者,您可以将它们传递给构造函数并将它们保存为成员变量。当你有多个这样的对象时,情况就会恶化。你正在线程化你的状态。在某些情况下,这不是问题。如果您知道只有两个或三个函数需要处理该有状态Store对象,那么这是更好的解决方案。
But in practice, that's not always the case. If every part of your app touches your Store, you will be threading it to a dozen functions. On top of that, some of those functions may have complicated business logic. When you break that business logic up with helper functions, you have to -- thread your state some more! Say for instance you realize that a deeply nested function needs some configuration data from the Store object. Suddenly, you have to edit 3 or 4 function declarations to include that store parameter. Then you have to go back and add the store as an actual parameter to everywhere one of those functions is called. It may be that the only use a function has for a Store is to pass it to some subfunction that needs it.
但在实践中,情况并非总是如此。如果您的应用程序的每个部分都触及您的商店,您将将其线程化为十几个功能。最重要的是,其中一些功能可能具有复杂的业务逻辑。当你使用辅助函数打破业务逻辑时,你必须 - 更多地处理你的状态!比如说你意识到深度嵌套的函数需要来自Store对象的一些配置数据。突然,您必须编辑3或4个函数声明以包含该store参数。然后你必须返回并将商店添加为实际参数,以便调用其中一个函数。可能是函数对Store的唯一用途是将它传递给需要它的某个子函数。
Patterns are just rules of thumb. Do you always use your turn signals before making a lane change in your car? If you're the average person, you'll usually follow the rule, but if you are driving at 4am on an empty high way, who gives a crap, right? Sometimes it'll bite you in the butt, but that's a managed risk.
模式只是经验法则。你是否总是在改变汽车换道前使用转向灯?如果你是一般人,你通常会遵循这个规则,但是如果你是在凌晨4点开空行驶的,那么谁给了垃圾,对吧?有时它会咬你的屁股,但这是一个有管理的风险。
#5
Regarding your inflated constructor call problem, you could introduce parameter classes or factory methods to leverage this problem for you.
关于膨胀的构造函数调用问题,您可以引入参数类或工厂方法来为您利用此问题。
A parameter class moves some of the parameter data to it's own class, e.g. like this:
参数类将一些参数数据移动到它自己的类,例如像这样:
var parameterClass1 = new MenuParameter(menuBar, editor);
var parameterClass2 = new StuffParameters(sasquatch, ...);
var ctrl = new MyControllerClass(managedStore, parameterClass1, parameterClass2);
It sort of just moves the problem elsewhere though. You might want to housekeep your constructor instead. Only keep parameters that are important when constructing/initiating the class in question and do the rest with getter/setter methods (or properties if you're doing .NET).
它只是将问题转移到其他地方。您可能希望改为维护构造函数。只保留构造/启动相关类时重要的参数,并使用getter / setter方法(如果您正在使用.NET,则执行属性)。
A factory method is a method that creates all instances you need of a class and have the benefit of encapsulating creation of the said objects. They are also quite easy to refactor towards from Singleton, because they're similar to getInstance methods that you see in Singleton patterns. Say we have the following non-threadsafe simple singleton example:
工厂方法是一种方法,它创建所需的类所有实例,并具有封装所述对象的创建的好处。它们也非常容易从Singleton重构,因为它们与您在Singleton模式中看到的getInstance方法类似。假设我们有以下非线程安全的简单单例示例:
// The Rather Unfortunate Singleton Class
public class SingletonStore {
private static SingletonStore _singleton
= new MyUnfortunateSingleton();
private SingletonStore() {
// Do some privatised constructing in here...
}
public static SingletonStore getInstance() {
return _singleton;
}
// Some methods and stuff to be down here
}
// Usage:
// var singleInstanceOfStore = SingletonStore.getInstance();
It is easy to refactor this towards a factory method. The solution is to remove the static reference:
很容易将其重构为工厂方法。解决方案是删除静态引用:
public class StoreWithFactory {
public StoreWithFactory() {
// If the constructor is private or public doesn't matter
// unless you do TDD, in which you need to have a public
// constructor to create the object so you can test it.
}
// The method returning an instance of Singleton is now a
// factory method.
public static StoreWithFactory getInstance() {
return new StoreWithFactory();
}
}
// Usage:
// var myStore = StoreWithFactory.getInstance();
Usage is still the same, but you're not bogged down with having a single instance. Naturally you would move this factory method to it's own class as the Store
class shouldn't concern itself with creation of itself (and coincidentally follow the Single Responsibility Principle as an effect of moving the factory method out).
用法仍然相同,但你不会因为拥有一个实例而陷入困境。当然,您可以将此工厂方法移动到它自己的类,因为Store类不应该关注自身的创建(并且巧合地遵循单一责任原则作为移动工厂方法的效果)。
From here you have many choices, but I'll leave that as an exercise for yourself. It is easy to over-engineer (or overheat) on patterns here. My tip is to only apply a pattern when there is a need for it.
从这里你有很多选择,但我会把它作为锻炼给自己。这里的模式很容易过度设计(或过热)。我的建议是仅在需要时应用模式。
#6
Okay, first of all, the "singletons are always evil" notion is wrong. You use a Singleton whenever you have a resource which won't or can't ever be duplicated. No problem.
好吧,首先,“单身人士总是邪恶的”概念是错误的。只要有资源不会或不能复制,就可以使用Singleton。没问题。
That said, in your example, there's an obvious degree of freedom in the application: someone could come along and say "but I want two stores."
也就是说,在你的例子中,应用程序中有一个明显的*度:有人可以过来说“我想要两个商店”。
There are several solutions. The one that occurs first of all is to build a factory class; when you ask for a Store, it gives you one named with some universal name (eg, a URI.) Inside that store, you need to be sure that multiple copies don't step on one another, via critical regions or some method of ensuring atomicity of transactions.
有几种解决方案。首先出现的是建造一个工厂阶级;当你要求一个商店时,它会给你一个带有一些通用名称的名字(例如,一个URI)。在那个商店里面,你需要确保多个副本不会通过关键区域或某些方法相互衔接。确保交易的原子性。
#7
Miško Hevery has a nice article series on testability, among other things the singleton, where he isn't only talking about the problems, but also how you might solve it (see 'Fixing the flaw').
MiškoHevery有一篇关于可测试性的精彩系列文章,其中包括单身人士,他不仅讨论问题,还讨论如何解决问题(参见“修复漏洞”)。
#8
I like to encourage the use of singletons where necessary while discouraging the use of the Singleton pattern. Note the difference in the case of the word. The singleton (lower case) is used wherever you only need one instance of something. It is created at the start of your program and is passed to the constructor of the classes that need it.
我喜欢鼓励在必要时使用单身人士,同时不鼓励使用单身人士模式。注意单词的区别。单例(小写)用于只需要一个实例的地方。它是在程序开始时创建的,并传递给需要它的类的构造函数。
class Log
{
void logmessage(...)
{ // do some stuff
}
};
int main()
{
Log log;
// do some more stuff
}
class Database
{
Log &_log;
Database(Log &log) : _log(log) {}
void Open(...)
{
_log.logmessage(whatever);
}
};
Using a singleton gives all of the capabilities of the Singleton anti-pattern but it makes your code more easily extensible, and it makes it testable (in the sense of the word defined in the Google testing blog). For example, we may decide that we need the ability to log to a web-service at some times as well, using the singleton we can easily do that without significant changes to the code.
使用单例提供了Singleton反模式的所有功能,但它使您的代码更容易扩展,并且使其可测试(在Google测试博客中定义的单词意义上)。例如,我们可能决定在某些时候也需要能够登录Web服务,使用我们可以轻松完成的单例,而无需对代码进行重大更改。
By comparison, the Singleton pattern is another name for a global variable. It is never used in production code.
相比之下,Singleton模式是全局变量的另一个名称。它从未在生产代码中使用。
#1
Dependency Injection is your friend.
依赖注入是你的朋友。
Take a look at these posts on the excellent Google Testing Blog:
在优秀的Google测试博客上查看这些帖子:
- Singletons are pathologic liars (but you probably already understand this if you are asking this question)
- A talk on Dependency Injection
- Guide to Writing Testable Code
单身人士是病态的骗子(但如果你问这个问题,你可能已经理解了这一点)
关于依赖注入的讨论
编写可测试代码的指南
Hopefully someone has made a DI framework/container for the C++ world? Looks like Google has released a C++ Testing Framework and a C++ Mocking Framework, which might help you out.
希望有人为C ++世界制作了DI框架/容器?看起来谷歌发布了一个C ++测试框架和一个C ++模拟框架,可能会帮助你。
#2
It's not the Singleton-ness that is the problem. It's fine to have an object that there will only ever be one instance of. The problem is the global access. Your classes that use Store should receive a Store instance in the constructor (or have a Store property / data member that can be set) and they can all receive the same instance. Store can even keep logic within it to ensure that only one instance is ever created.
这不是单身人士的问题。拥有一个只有一个实例的对象,这很好。问题是全球访问。您使用Store的类应该在构造函数中接收Store实例(或者具有可以设置的Store属性/数据成员),并且它们都可以接收相同的实例。 Store甚至可以在其中保留逻辑,以确保只创建一个实例。
#3
My way to avoid singletons derives from the idea that "application global" doesn't mean "VM global" (i.e. static
). Therefore I introduce a ApplicationContext
class which holds much former static
singleton information that should be application global, like the configuration store. This context is passed into all structures. If you use any IOC container or service manager, you can use this to get access to the context.
我避免单身人士的方法源于“应用程序全局”并不意味着“虚拟机全局”(即静态)的观点。因此,我介绍了一个ApplicationContext类,它包含许多以前应该是应用程序全局的静态单例信息,就像配置存储一样。此上下文将传递到所有结构中。如果您使用任何IOC容器或服务管理器,则可以使用它来访问上下文。
#4
There's nothing wrong with using a global or a singleton in your program. Don't let anyone get dogmatic on you about that kind of crap. Rules and patterns are nice rules of thumb. But in the end it's your project and you should make your own judgments about how to handle situations involving global data.
在程序中使用全局或单例没有任何问题。不要让任何人对你说这种废话。规则和模式是很好的经验法则。但最终这是你的项目,你应该对如何处理涉及全局数据的情况做出自己的判断。
Unrestrained use of globals is bad news. But as long as you are diligent, they aren't going to kill your project. Some objects in a system deserve to be singleton. The standard input and outputs. Your log system. In a game, your graphics, sound, and input subsystems, as well as the database of game entities. In a GUI, your window and major panel components. Your configuration data, your plugin manager, your web server data. All these things are more or less inherently global to your application. I think your Store class would pass for it as well.
无限制地使用全局变量是个坏消息。但只要你勤奋,他们就不会杀了你的项目。系统中的某些对象应该是单例。标准输入和输出。你的日志系统。在游戏中,您的图形,声音和输入子系统,以及游戏实体的数据库。在GUI中,您的窗口和主要面板组件。您的配置数据,插件管理器,Web服务器数据。所有这些事情或多或少都与您的应用程序具有全局性。我认为你的Store类也会传递它。
It's clear what the cost of using globals is. Any part of your application could be modifying it. Tracking down bugs is hard when every line of code is a suspect in the investigation.
很清楚使用全局变量的成本是多少。您的应用程序的任何部分都可能正在修改它。当每行代码都是调查中的嫌疑人时,追踪错误很难。
But what about the cost of NOT using globals? Like everything else in programming, it's a trade off. If you avoid using globals, you end up having to pass those stateful objects as function parameters. Alternatively, you can pass them to a constructor and save them as a member variable. When you have multiple such objects, the situation worsens. You are now threading your state. In some cases, this isn't a problem. If you know only two or three functions need to handle that stateful Store object, it's the better solution.
但是不使用全局变量的成本呢?就像编程中的其他一切一样,这是一种权衡。如果避免使用全局变量,则最终必须将这些有状态对象作为函数参数传递。或者,您可以将它们传递给构造函数并将它们保存为成员变量。当你有多个这样的对象时,情况就会恶化。你正在线程化你的状态。在某些情况下,这不是问题。如果您知道只有两个或三个函数需要处理该有状态Store对象,那么这是更好的解决方案。
But in practice, that's not always the case. If every part of your app touches your Store, you will be threading it to a dozen functions. On top of that, some of those functions may have complicated business logic. When you break that business logic up with helper functions, you have to -- thread your state some more! Say for instance you realize that a deeply nested function needs some configuration data from the Store object. Suddenly, you have to edit 3 or 4 function declarations to include that store parameter. Then you have to go back and add the store as an actual parameter to everywhere one of those functions is called. It may be that the only use a function has for a Store is to pass it to some subfunction that needs it.
但在实践中,情况并非总是如此。如果您的应用程序的每个部分都触及您的商店,您将将其线程化为十几个功能。最重要的是,其中一些功能可能具有复杂的业务逻辑。当你使用辅助函数打破业务逻辑时,你必须 - 更多地处理你的状态!比如说你意识到深度嵌套的函数需要来自Store对象的一些配置数据。突然,您必须编辑3或4个函数声明以包含该store参数。然后你必须返回并将商店添加为实际参数,以便调用其中一个函数。可能是函数对Store的唯一用途是将它传递给需要它的某个子函数。
Patterns are just rules of thumb. Do you always use your turn signals before making a lane change in your car? If you're the average person, you'll usually follow the rule, but if you are driving at 4am on an empty high way, who gives a crap, right? Sometimes it'll bite you in the butt, but that's a managed risk.
模式只是经验法则。你是否总是在改变汽车换道前使用转向灯?如果你是一般人,你通常会遵循这个规则,但是如果你是在凌晨4点开空行驶的,那么谁给了垃圾,对吧?有时它会咬你的屁股,但这是一个有管理的风险。
#5
Regarding your inflated constructor call problem, you could introduce parameter classes or factory methods to leverage this problem for you.
关于膨胀的构造函数调用问题,您可以引入参数类或工厂方法来为您利用此问题。
A parameter class moves some of the parameter data to it's own class, e.g. like this:
参数类将一些参数数据移动到它自己的类,例如像这样:
var parameterClass1 = new MenuParameter(menuBar, editor);
var parameterClass2 = new StuffParameters(sasquatch, ...);
var ctrl = new MyControllerClass(managedStore, parameterClass1, parameterClass2);
It sort of just moves the problem elsewhere though. You might want to housekeep your constructor instead. Only keep parameters that are important when constructing/initiating the class in question and do the rest with getter/setter methods (or properties if you're doing .NET).
它只是将问题转移到其他地方。您可能希望改为维护构造函数。只保留构造/启动相关类时重要的参数,并使用getter / setter方法(如果您正在使用.NET,则执行属性)。
A factory method is a method that creates all instances you need of a class and have the benefit of encapsulating creation of the said objects. They are also quite easy to refactor towards from Singleton, because they're similar to getInstance methods that you see in Singleton patterns. Say we have the following non-threadsafe simple singleton example:
工厂方法是一种方法,它创建所需的类所有实例,并具有封装所述对象的创建的好处。它们也非常容易从Singleton重构,因为它们与您在Singleton模式中看到的getInstance方法类似。假设我们有以下非线程安全的简单单例示例:
// The Rather Unfortunate Singleton Class
public class SingletonStore {
private static SingletonStore _singleton
= new MyUnfortunateSingleton();
private SingletonStore() {
// Do some privatised constructing in here...
}
public static SingletonStore getInstance() {
return _singleton;
}
// Some methods and stuff to be down here
}
// Usage:
// var singleInstanceOfStore = SingletonStore.getInstance();
It is easy to refactor this towards a factory method. The solution is to remove the static reference:
很容易将其重构为工厂方法。解决方案是删除静态引用:
public class StoreWithFactory {
public StoreWithFactory() {
// If the constructor is private or public doesn't matter
// unless you do TDD, in which you need to have a public
// constructor to create the object so you can test it.
}
// The method returning an instance of Singleton is now a
// factory method.
public static StoreWithFactory getInstance() {
return new StoreWithFactory();
}
}
// Usage:
// var myStore = StoreWithFactory.getInstance();
Usage is still the same, but you're not bogged down with having a single instance. Naturally you would move this factory method to it's own class as the Store
class shouldn't concern itself with creation of itself (and coincidentally follow the Single Responsibility Principle as an effect of moving the factory method out).
用法仍然相同,但你不会因为拥有一个实例而陷入困境。当然,您可以将此工厂方法移动到它自己的类,因为Store类不应该关注自身的创建(并且巧合地遵循单一责任原则作为移动工厂方法的效果)。
From here you have many choices, but I'll leave that as an exercise for yourself. It is easy to over-engineer (or overheat) on patterns here. My tip is to only apply a pattern when there is a need for it.
从这里你有很多选择,但我会把它作为锻炼给自己。这里的模式很容易过度设计(或过热)。我的建议是仅在需要时应用模式。
#6
Okay, first of all, the "singletons are always evil" notion is wrong. You use a Singleton whenever you have a resource which won't or can't ever be duplicated. No problem.
好吧,首先,“单身人士总是邪恶的”概念是错误的。只要有资源不会或不能复制,就可以使用Singleton。没问题。
That said, in your example, there's an obvious degree of freedom in the application: someone could come along and say "but I want two stores."
也就是说,在你的例子中,应用程序中有一个明显的*度:有人可以过来说“我想要两个商店”。
There are several solutions. The one that occurs first of all is to build a factory class; when you ask for a Store, it gives you one named with some universal name (eg, a URI.) Inside that store, you need to be sure that multiple copies don't step on one another, via critical regions or some method of ensuring atomicity of transactions.
有几种解决方案。首先出现的是建造一个工厂阶级;当你要求一个商店时,它会给你一个带有一些通用名称的名字(例如,一个URI)。在那个商店里面,你需要确保多个副本不会通过关键区域或某些方法相互衔接。确保交易的原子性。
#7
Miško Hevery has a nice article series on testability, among other things the singleton, where he isn't only talking about the problems, but also how you might solve it (see 'Fixing the flaw').
MiškoHevery有一篇关于可测试性的精彩系列文章,其中包括单身人士,他不仅讨论问题,还讨论如何解决问题(参见“修复漏洞”)。
#8
I like to encourage the use of singletons where necessary while discouraging the use of the Singleton pattern. Note the difference in the case of the word. The singleton (lower case) is used wherever you only need one instance of something. It is created at the start of your program and is passed to the constructor of the classes that need it.
我喜欢鼓励在必要时使用单身人士,同时不鼓励使用单身人士模式。注意单词的区别。单例(小写)用于只需要一个实例的地方。它是在程序开始时创建的,并传递给需要它的类的构造函数。
class Log
{
void logmessage(...)
{ // do some stuff
}
};
int main()
{
Log log;
// do some more stuff
}
class Database
{
Log &_log;
Database(Log &log) : _log(log) {}
void Open(...)
{
_log.logmessage(whatever);
}
};
Using a singleton gives all of the capabilities of the Singleton anti-pattern but it makes your code more easily extensible, and it makes it testable (in the sense of the word defined in the Google testing blog). For example, we may decide that we need the ability to log to a web-service at some times as well, using the singleton we can easily do that without significant changes to the code.
使用单例提供了Singleton反模式的所有功能,但它使您的代码更容易扩展,并且使其可测试(在Google测试博客中定义的单词意义上)。例如,我们可能决定在某些时候也需要能够登录Web服务,使用我们可以轻松完成的单例,而无需对代码进行重大更改。
By comparison, the Singleton pattern is another name for a global variable. It is never used in production code.
相比之下,Singleton模式是全局变量的另一个名称。它从未在生产代码中使用。