Skip to content

Commit

Permalink
Added notes and code for the Singleton design pattern.
Browse files Browse the repository at this point in the history
  • Loading branch information
lottlizard committed Oct 30, 2012
1 parent e111e73 commit 05a0858
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 0 deletions.
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,50 @@ For the `w` instance of `SimpleWriter`, the original `write_line` method still e
disadvantage of using extend with modules:
- can't easily remove modules
---
### SINGLETON
The singleton pattern is used to ensure that there is only one instance of a class and provides global access to that instance.
This pattern is useful when you want one instance of a class and many different objects need to access it, rather than pass the object around, we can make the object global.
GoF: Let the class of the singleton object manage the creation and access to its sole instance.
The Ruby standard library includes a [Singleton module](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/singleton/rdoc/Singleton.html) module.
The `singleton module` is thorough, it overrides multiple methods to prevent multiple instances of the singleton class. It also uses lazy instantiation, creating the instance only once the `instance` method is called.
#### Alternatives
##### Global Variables
As an alternative, it is possible to use global variables to store singletons. There can be only one instance of a global variable and by definition they are globally accessible.
Disadvantages:
* Global variables can be reassigned at any time.
* Lazy instantiation isn't possible.

##### Constants
Since we can use global variables to hold singletons, it follows that we can also constants.

Disadvantages:

* Constant variables can be reassigned at any time. A warning is returned when they are changed but they are still changed.
* Lazy instantiation isn'e possible.
* We can't prevent the creation of more than one instance of the singleton class.

##### Classes as Singletons
Disadvantages:

* Using a class to hold all the variables and methods doesn't follow traditional coding conventions.
Advantages:
* There can be only one class of a given name and therefore only one instance of the singleton.
##### Modules as Singletons
The code is exactly the same as using a class as a singleton, except we define a module instead of a class.
A module is a collection of methods and variables, but unlike classes, modules cannot be instantiated. Because of this, using a module for a singleton better adheres to coding conventions and makes for clearer code.
Expand Down
21 changes: 21 additions & 0 deletions singleton/Logger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Logger
attr_reader :log

def initialize
@log = File.open('log.txt', 'a')
end

@@instance = self.new

def self.instance
return @@instance
end

# def log(msg)
# @log.puts(msg)
# end

private_class_method :new
end

Logger.instance.log
40 changes: 40 additions & 0 deletions singleton/SimpleLogger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'singleton'

class SimpleLogger
include Singleton

attr_accessor :level

ERROR = 1
WARNING = 2
INFO = 3

def initialize
@log = File.open('log.txt', 'w')
@level = WARNING
end

## the Singleton module overrides the following code
# @@instance = self.new
#
# def self.instance
# @@instance
# end
#
# private_class_method :new

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
35 changes: 35 additions & 0 deletions singleton/class_as_singleton/ClassBasedLogger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class ClassBasedLogger
ERROR = 1
WARNING = 2
INFO = 3

@@level = WARNING

# Lazily instantiate @@log
def self.log
@@log ||= File.open('log.txt', 'w')
end

def self.error(msg)
log.puts("Error: #{msg}")
log.flush
end

def self.warning(msg)
log.puts("Warning: #{msg}") if @@level >= WARNING
log.flush
end

def self.info(msg)
log.puts("Info: #{msg}") if @@level >= INFO
log.flush
end

def self.level=(new_level)
@@level = new_level
end

def self.level
@@level
end
end
3 changes: 3 additions & 0 deletions singleton/class_as_singleton/log.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Info: Computer wins chess game.
Warning: AE-35 hardware failure predicted.
Error: HAL-9000 malfunction, take emergency action!
6 changes: 6 additions & 0 deletions singleton/class_as_singleton/main.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require './ClassBasedLogger'

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!')
8 changes: 8 additions & 0 deletions singleton/main.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require './SimpleLogger'

logger = SimpleLogger.instance
puts logger.level

SimpleLogger.instance.info('Computer wins chess game.')
SimpleLogger.instance.warning('AE-35 hardware failure predicted.')
SimpleLogger.instance.error('HAL-9000 malfunction, take emergency action!')
35 changes: 35 additions & 0 deletions singleton/module_as_singleton/ModuleBasedLogger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module ModuleBasedLogger
ERROR = 1
WARNING = 2
INFO = 3

@@level = WARNING

# Lazily instantiate @@log
def self.log
@@log ||= File.open('log.txt', 'w')
end

def self.error(msg)
log.puts("Error: #{msg}")
log.flush
end

def self.warning(msg)
log.puts("Warning: #{msg}") if @@level >= WARNING
log.flush
end

def self.info(msg)
log.puts("Info: #{msg}") if @@level >= INFO
log.flush
end

def self.level=(new_level)
@@level = new_level
end

def self.level
@@level
end
end
3 changes: 3 additions & 0 deletions singleton/module_as_singleton/log.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Info: Computer wins chess game.
Warning: AE-35 hardware failure predicted.
Error: HAL-9000 malfunction, take emergency action!
6 changes: 6 additions & 0 deletions singleton/module_as_singleton/main.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require './ModuleBasedLogger'

ModuleBasedLogger.level = ModuleBasedLogger::INFO
ModuleBasedLogger.info('Computer wins chess game.')
ModuleBasedLogger.warning('AE-35 hardware failure predicted.')
ModuleBasedLogger.error('HAL-9000 malfunction, take emergency action!')

0 comments on commit 05a0858

Please sign in to comment.