Pity the poor Singleton pattern. Even coders who do not know very much about patterns know about the singleton. Mainly they know one thing: Singletons are Bad, with a capital "B". And yet we cannot seem to live without the things. Singletons are everywhere. In the Java world, singletons show up in some of the most widely used software around—you will find them in tomcat, in ant, and in JDOM. On the Ruby side, we can find singletons lurking in Webrick, in rake, and even in Rails, just to name a few.
What is it about the Singleton pattern that makes it so indispensable and yet so widely detested? In the pages that follow we will look at why you might need a singleton, how you would go about building singletons and singleton-like things in Ruby, why singletons cause trouble, and what you can do to ease some of this pain.
The motivation behind the Singleton pattern is very simple: There are some things that are unique. Programs frequently have a single configuration file. It is not unusual for a program to let you know how it is doing via a single log file. GUI applications frequently have a one main window, and they typically take input from exactly one keyboard. Many applications need to talk to exactly one database. If you only ever have one instance of a class and a lot of code that needs access to that instance, it seems silly to pass the object from one method to another. In this kind of situation, the GoF suggest that you build a singleton—a class that can have only one instance and that provides global access to that one instance.
There are a number of different ways that you can get some or all of the singleton behavior in Ruby, but we will start with the method that is closest to the one recommended by the GoF: Let the class of the singleton object manage the creation and access to its sole instance. To do so, we need to look first at class variables and class methods in Ruby.
So far, all of the code that we have written in this book has involved instance methods and variables—that is, code and data that are attached to individual instances of a class. Ruby, like most object-oriented languages, also supports class variables and methods, which are attached to a class.[1]
As we have seen, a class variable is a variable that is attached to a class[2] instead of to an instance of the class. Creating a class variable is very straightforward: You simply add another at sign (@) to the variable name. Here, for example, is a class that counts the number of times the increment method is called in two different variables—once in an instance variable and once in a class variable:
class ClassVariableTester
@@class_count = 0
def initialize
@instance_count = 0
end
def increment
@@class_count = @@class_count + 1
@instance_count = @instance_count + 1
end
def to_s
"class_count: #{@@class_count} instance_count: #{@instance_count}"
end
end
Now let’s create an instance named ClassVariableTester and call its increment method a couple of times:
c1 = ClassVariableTester.new
c1.increment
c1.increment
puts("c1: #{c1}")
Not surprisingly, both counts end up being 2:
c1: class_count: 2 instance_count: 2
Things get more interesting when you create a second instance of the class:
c2 = ClassVariableTester.new
puts("c2: #{c2}")
This produces
c2: class_count: 2 instance_count: 0
What is happening here is that the instance counter was reset to zero for the second ClassVariableTester instance, whereas the class counter, which is shared by both instances, keeps right on counting.
Creating class-level methods in Ruby is a bit more challenging, but only a bit. We cannot just open a class and define a method:
class SomeClass
def a_method
puts('hello from a method')
end
end
As we have already seen, if we do that we end up with an instance method:
SomeClass.a_method
instance.rb:11: undefined method 'a_method' for SomeClass:Class
The secret to creating a class method is knowing that when you are inside a class definition—but outside a method definition—the self variable is the class you are defining. You do not have to take my word for it, however. Suppose you run this class definition:
class SomeClass
puts("Inside a class def, self is #{self}")
end
You will see the following output:
Inside a class def, self is SomeClass
With this useful bit of information in hand, we can define a method on the class:
class SomeClass
def self.class_level_method
puts('hello from the class method')
end
end
We can now call class_level_method exactly as its name suggests, at the class level:
SomeClass.class_level_method
If you do not like the self.method_name syntax, Ruby offers another option. You can just define the class method by calling out the name explicitly:
class SomeClass
def SomeClass.class_level_method
puts('hello from the class method')
end
end
Ruby programmers seem evenly split on this syntactical conundrum: Some like self, and some like the explicit class name. Personally, I like the self format, because you have less to change if you rename the class or transplant code to another class.
Now that we know how to create class variables and methods, we have all the tools we need to create a singleton. Let’s start with an ordinary, non-singleton class (a multiton?) and transform it into a singleton. Perhaps you have a logging class, a little facility for keeping track of the comings and goings of your program. Your ordinary, non-singleton version of the logging class might look something like this:
class SimpleLogger
attr_accessor :level
ERROR = 1
WARNING = 2
INFO = 3
def initialize
@log = File.open("log.txt", "w")
@level = WARNING
end
def error(msg)
@log.puts(msg)
@log.flush
end
def warning(msg)
@log.puts(msg) if @level >= WARNING
@log.flush
end
def info(msg)
@log.puts(msg) if @level >= INFO
@log.flush
end
end
You might use this version of the logger by creating a new one and passing it around:
logger = SimpleLogger.new
logger.level = SimpleLogger::INFO
logger.info('Doing the first thing')
# Do the first thing...
logger.info('Now doing the second thing')
# Do the second thing...
The whole point of the Singleton pattern is to avoid passing an object like the logger all over the place. Instead, you want to make the SimpleLogger class responsible for managing its single instance. So how would you turn SimpleLogger into a singleton?
First, you add a class variable to hold the one and only instance of your class. You will also need a class method to return the singleton instance.
class SimpleLogger
# Lots of code deleted...
@@instance = SimpleLogger.new
def self.instance
return @@instance
end
end
We can now call the instance method of the SimpleLogger class any number of times and always get back the same logger object:
logger1 = SimpleLogger.instance # Returns the logger
logger2 = SimpleLogger.instance # Returns exactly the same logger
More practically, we can get at the singleton logger from anywhere in our code and use it to write out messages:
SimpleLogger.instance.info('Computer wins chess game.')
SimpleLogger.instance.warning('AE-35 hardware failure predicted.')
SimpleLogger.instance.error(
'HAL-9000 malfunction, take emergency action!')
Our singleton is now sort of functional, but it is not really complete. Remember, one requirement of the singleton is to ensure that the one and only singleton is the sole instance of the singleton class. So far we have ignored this requirement. As things stand right now, any program can call SimpleLogger.new to make a second instance of our allegedly singleton class. So how do we go about securing SimpleLogger against promiscuous instantiation?
We do so by making the new method on SimpleLogger private:
class SimpleLogger
# Lots of code deleted...
@@instance = SimpleLogger.new
def self.instance
return @@instance
end
private_class_method :new
end
There are two ideas to take away from this code fragment, one a detail and the other a bit more profound. The detail is that by adding the private_class_method call, we have done exactly what the name suggests: We made the new class method private, preventing any other class from creating new instances of our logger. The broader issue is that new is just another class-level method. Yes, the new method does perform some special behind-the-scenes magic in allocating a new object, but in the end it is just another class-level method.
Our singleton implementation is now complete, in that we have all of the ingredients required of a full-fledged GoF singleton. Our class creates exactly one instance of itself, any code that is interested can access the single instance, and no one can ever create a second instance.
Our singleton implementation does appear to have one problem, however. What if we want to build a second singleton class, perhaps for our configuration data? It seems that we will need to go through the whole exercise again: create a class variable for the singleton instance along with a class method to access it. Oh, and don’t forget to make the new method private. If we need a third instance, we need to do it all again a third time. This seems like a lot of duplicated effort.
Fortunately, we can avoid working so hard. Instead of going through all of the pain of turning our classes into singletons by hand, we can just include the Singleton module:
require 'singleton'
class SimpleLogger
include Singleton
# Lots of code deleted...
end
The Singleton module does all of the heavy lifting of creating the class variable and initializing it with the singleton instance, creating the class-level instance method, and making new private. All we need to do is include the module. From the outside, this new Singleton module-based logger looks exactly like our previous hand-built implementations: Just call SimpleLogger.instance to retrieve the instance and off you go.
There is one significant difference between the singleton implementation that we constructed and the one provided by the Singleton module. Recall that our implementation created the singleton instance as the class was being defined:
class SimpleLogger
# Lots of code deleted...
@@instance = SimpleLogger.new
# Lots of code deleted...
end
As a consequence, our singleton instance is created before any client code ever gets a chance to call SimpleLogger.instance. Creating the singleton instance before you actually need it is called eager instantiation—we just can’t wait to make the thing. The Singleton module, by contrast, waits until someone calls instance before it actually creates its singleton. This technique is known as lazy instantiation.
While the class-managed technique for building singletons that we have introduced here closely follows the implementation recommended in Design Patterns, it by no means exhausts the possibilities for realizing some or all of the singleton behavior. There are a number of other alternatives that we might use to achieve the same effect.
We might, for example, use a global variable as a singleton. I will pause here while the screams of horror die down. In Ruby, any variable whose name begins with a dollar sign—$logger, for example—is global. Global variables certainly have the global access part of the singleton routine down pat: You can access $logger in any context, in any class, module, or method, and it will always be the same $logger. Because there is only one instance of any given global variable and because that variable is available everywhere (it being global and all), global variables seem like they might be a good platform for implementing singletons.
Sadly, no. Global variables lack some of the fundamental moving parts of a singleton. While $logger always refers to exactly one object at any given time, there is no way to control the value of a global variable. While we might start off with our global pseudo-singleton carefully set to the right thing:
$logger = SimpleLogger.new
But there is absolutely nothing to prevent some misguided code from changing it:
$logger = LoggerThatDoesSomethingBad.new
If change is the problem, then maybe we should turn to a flavor of Ruby variable that not only has global scope but also resists change: the constant. Recall that a Ruby constant is a variable whose name starts with an uppercase letter and has the nice property that, once set, its value is not supposed to change:
Logger = SimpleLogger.new
Recall from Chapter 2 that Ruby will complain if we change the value of a constant, which is at least an improvement in attitude over the "anything goes" philosophy of global variables. So is this the simple solution to the singleton?
Not really. Both global variables and constants share a number of deficiencies as singletons. First, if you use a global variable or a constant for this purpose, there is no way to delay the creation of the singleton object until you need it. The global variable or constant is there from the moment we first set it. Second, neither of these techniques does anything to prevent someone from creating a second or third instance of your supposedly singleton class. You could, of course, deal with that issue separately. For example, you might create the singleton instance and then change the class so that it will refuse to create any more instances—but all of this is beginning to feel rather ad hoc and messy.
Given that global variables and constants seem to fall short, are there any other ways to do the singleton thing?
As we have seen, we can define methods and variables directly on a class object. In fact, our original singleton implementation used class methods and variables to manage the singleton instance. But given that we can have methods and variables on a class, why not just use the class itself as a container for the singleton functionality? Each class is unique—there can be only one SimpleLogger class loaded at any one time—so we might just define our singleton functionality as class methods and variables on a class object:
class ClassBasedLogger
ERROR = 1
WARNING = 2
INFO = 3
@@log = File.open('log.txt', 'w')
@@level = WARNING
def self.error(msg)
@@log.puts(msg)
@@log.flush
end
def self.warning(msg)
@@log.puts(msg) if @@level >= WARNING
@@log.flush
end
def self.info(msg)
@@log.puts(msg) if @@level >= INFO
@@log.flush
end
def self.level=(new_level)
@@level = new_level
end
def self.level
@@level
end
end
Using the class-based singleton is not hard:
ClassBasedLogger.level = ClassBasedLogger::INFO
ClassBasedLogger.info('Computer wins chess game.')
ClassBasedLogger.warning('AE-35 hardware failure predicted.')
ClassBasedLogger.error('HAL-9000 malfunction, take emergency action!')
The "class as singleton" technique has a key advantage over the global variable and constant methods: You are sure that no one will create a second instance of your singleton. Lazy initialization remains a problem with this technique, however. Specifically, your class is initialized when it gets loaded (typically when someone requires the file that the class lives in), and you do not have a lot of control over the timing of this initialization. Another disadvantage of using a class as a singleton is that programming class methods and variables is just not as easy as coding garden-variety instance methods and variables; all of those self.methods and @@variables have a strange feel to them.
Another possibility is to use a module as the container for your singleton behavior. As noted earlier in this chapter, modules have a lot in common with classes. In fact, modules are so much like classes that you can define module-level methods and variables in exactly the same way that you define class methods and variables. Except for changing class to module, the module-based implementation is exactly the same as the class-based one:
module ModuleBasedLogger
ERROR = 1
WARNING = 2
INFO = 3
@@log = File.open("log.txt", "w")
@@level = WARNING
def self.error(msg)
@@log.puts(msg)
@@log.flush
end
# Lots of code, exactly like the
# ClassBasedSingleton deleted...
end
You can use module methods from just about anywhere, just like class methods:
ModuleBasedLogger.info('Computer wins chess game.')
The "module as singleton" technique does have one notable advantage over the "class as singleton" technique. Because you cannot instantiate a module (that is the key difference between a module and a class), the intent of a module-based singleton is probably a bit clearer from the code: Here is a bucket of methods meant to be called and not something you can instantiate.
The discussion of the alternative ways of implementing the Singleton pattern raises the question of language-based safety features, and what such features can mean in a language as flexible as Ruby. To reach for a handy example, we have seen that one of the effects of including the Singleton module is to make the new method private. This, of course, prevents anyone from making a second or third instance of the singleton class. If our singleton class is defined as
require 'singleton'
class Manager
include Singleton
def manage_resources
puts("I am managing my resources")
end
end
I cannot make another instance of Manager. For example, if I try
m = Manager.new
I will get
private method 'new' called for Manager:Class
Actually, the Singleton module cannot really prevent anything. All I need is a little insight into how Singleton works and a bit of knowledge about public_class_method (the evil twin of private_class_method), and it becomes very easy to circumvent all of that prevention:
class Manager
public_class_method :new
end
m = Manager.new
In the same spirit, we noted earlier that one advantage of the class- or module-based singleton is that no one can make a second instance of your singleton. Well, not by accident, they can’t. But no matter whether you are using ClassBasedLogger or its cousin ModuleBasedLogger, your logger is in the end an object, and all objects in Ruby inherit the clone method. The clone method is wonderful utility for short-circuiting that singleton-ness that we have been working so hard to establish:
a_second_logger = ClassBasedLogger.clone
a_second_logger.error('using a second logger')
We might, of course, override the clone method in ClassBasedLogger to prevent unauthorized cloning. Of course, the determined cloner could just reopen your class to un-override the method . . .
The point is not that this kind of thing is a good idea, but rather that in a language where virtually everything done at runtime can be undone a little later in runtime, very few decisions are irreversible. The Ruby philosophy is that if you decide to circumvent the very clear intent of the author of the ClassBasedLogger class by cloning it, the language is there to help you out. You are in the driver's seat, not the language. By keeping almost everything open to modification, Ruby allows you to do the things that you say you want to do—but it is up to you to say the right things.
Now that we know how to build a singleton, let’s figure out why this is perhaps the most hated of all patterns.
Let’s start with the most obvious problem first: A singleton bears a very strong family resemblance to its outlaw cousin, the global variable. No matter whether you implement your singleton with the GoF class-managed technique or as a bunch of class- or module-level methods and variables, you are creating a single object with global scope. Create a singleton, and you have just made it possible for widely separated bits of your program to use that singleton as a secret channel to communicate with each other and, in the process, tightly couple themselves to each other. The horrible consequences of this coupling are why software engineering got out of the global variable business in the first place.
There is only one solution to this problem: Don’t do that. Properly applied, singletons are not global variables. Rather, they are meant to model things that occur exactly once. Yes, because it occurs only once, you can use a singleton as a unique communications conduit between bits of your program. But don’t do that. Singletons are like every other pattern and programming technique—which means you can really screw things up if you abuse them. I can only repeat: Don’t do that.
Which brings us to another obvious-sounding, but all-too-common way to come to grief with the Singleton pattern: to lose count. As you are considering applying the Singleton pattern, ask yourself this question: Am I sure that there is only one of these things? The Singleton pattern gives us a way to model a single instance of something, but this modeling also just happens to come with a nice coding feature that makes that single instance very easily accessible—just call SimpleLogger.instance. That easy access can have a hypnotic allure: "My code will be so much simpler if this thing is a singleton." Don’t listen to the siren song of that easy access. Instead, focus on the question of how many of these things exist and treat the easy access as a bonus.
Another mistake that many people make is to spread the knowledge of a class's singleton-ness far and wide. You can look at the fact that a class is a singleton as something of an implementation detail: Once you get hold of the configuration file, exactly how you got hold of it is not really important. Remember that you can always grab the singleton object in one or a few places and then pass it around from there.
This technique comes in handy when your application needs to use the singleton in a few widely scattered clusters of code. For example, you might have an application structured like the one shown in Figure 12-1.
Figure 12-1. An application with widely scattered uses of a singleton
Imagine that the PreferenceManager class and the classes that it uses need access to a database connection, as does the DataPersistence class and its friends. Further imagine that the entire application uses a single instance of the class DatabaseConnectionManager for all of its connection management needs. Recognizing this, you make DatabaseConnectionManager a singleton:
require 'singleton'
class DatabaseConnectionManager
include Singleton
def get_connection
# Return the database connection...
end
end
Now here's the question: Which classes are actually aware that DatabaseConnectionManager is a singleton? We could spread this information far and wide, perhaps among the preference readers and writers:
class PreferenceManager
def initialize
@reader = PrefReader.new
@writer = PrefWriter.new
@preferences = { :display_splash=>false, :background_color=>:blue }
end
def save_preferences
preferences = {}
# Preference are in
@writer.write(@preferences)
end
def get_preferences
@preferences = @reader.read
end
end
class PrefWriter
def write(preferences)
connection = DatabaseConnectionManager.instance.get_connection
# Write the preferences out
end
end
class PrefReader
def read
connection = DatabaseConnectionManager.instance.get_connection
# Read the preferences and return them...
end
end
A better approach might be to concentrate the knowledge that DatabaseConnectionManager is a singleton in the PreferenceManager class and simply pass it into the preference reader and writer:
class PreferenceManager
def initialize
@reader = PrefReader.new
@writer = PrefWriter.new
@preferences = { :display_splash=>false, :background_color=>:blue }
end
def save_preferences
preferences = {}
# Preference are in
@writer.write(DatabaseConnectionManager.instance, @preferences)
end
def get_preferences
@preferences = @reader.read(DatabaseConnectionManager.instance)
end
end
This little refactoring decreases the amount of code that needs to know that DatabaseConnectionManager is a singleton. There are two advantages to doing this. First, there is less code to fix if it turns out that your singleton is not, in fact, quite so alone. Second, by excising the singleton from the PrefReader and PrefWriter classes, you have made those classes much more easily testable.
This last point brings us to testing. One exceedingly nasty thing about the Singleton pattern is the way that it interferes with unit testing. A good unit test needs to start with a known state. After all, your test results are unlikely to be worth much if you aren’t sure how things were set up when you started the test. A good unit test also needs to be independent of any other test, so that test 3 should give you exactly the same results no matter whether you run it between tests 2 and 4, after test 20, or all by itself. The problem, of course, is that if tests 1 through 20 are testing a singleton, each test is liable to modify the one and only singleton instance in some unpredictable way. So much for test independence.
One way to deal with this problem is to create two classes: an ordinary (i.e., non-singleton) class that contains all of the code, and a subclass of the first class that is a singleton. Something like this:
require 'singleton'
class SimpleLogger
# All of the logging functionality in this class...
end
class SingletonLogger < SimpleLogger
include Singleton
end
The actual application code uses the SingletonLogger, while the tests can use the plain old, non-singleton Logger class.
You can find a good example of the use of the Singleton pattern in real life in ActiveSupport, which is a library of utility classes used by Rails. Rails relies heavily on the use of conventions, and many of the Rails conventions involve working out the plurals of singular words and the singulars of plural words. To do so, ActiveSupport maintains a list of rules, which encapsulate facts like "The plural of employee is employees, but the plural of criterion is criteria." But since the rules are, well, the rules, you really need to keep only one copy of them around. So the Inflections class is a singleton, which saves space and ensures that the same inflection rules are available everywhere.
Ruby’s build utility, rake, also uses a singleton. As it runs, rake—like most build tools—reads in information about what it needs to do: which directories to create, which files to copy, and so on.[3] All of this information needs to be available to all of the moving parts of rake, so rake stores it all in a single object (the Rake::Application object, to be precise) that is available as a singleton to the entire rake program.
In this chapter, we looked at the somewhat checkered career of the Singleton pattern. The Singleton pattern can help us deal with the cases where there is only one of something. There are two characteristics that make a singleton a singleton: A singleton class has exactly one instance, and access to that one instance is available globally. Using class methods and variables, we can easily build the "classic" implementation of the singleton, the one recommended by the GoF.
We can also build singletons (or at least near-singletons) using a variety of other methods. For example, we could get some of the singleton behavior from global variables or constants, although these elements lack the uniqueness characteristic that makes a real singleton a singleton. In addition, we can build singletons from class- or module-level methods and variables.
We spent a fair bit of time in this chapter looking at the landmines scattered around Singleton-land. We saw that the singleton presents rich opportunities for coupling your code to itself in very unfortunate ways. We also saw that you might want to limit the amount of code that is aware of an object's singleton-ness, and we looked at one way to ease the burden that singletons place on testing.
The Singleton pattern is a bit like that ancient table saw that my dad used to have. That saw was incredibly effective at cutting lumber, but, since it had very few safety features, it was equally adept at slicing an unwary hand in two.
3.135.193.124