Singleton Design Pattern
CECS277
Fall 2017
Mimi Opkins
Singleton Design Pattern
• Singleton pattern is one of the simplest design patterns in
Java.
• This type of design pattern comes under creational pattern as
this pattern provides one of the best ways to create an object.
• This pattern involves a single class which is responsible to
create an object while making sure that only single object gets
created.
• This class provides a way to access its only object which can be
accessed directly without need to instantiate the object of the
class.
Example: Logger
What is wrong with this code?
public class Logger
{
public Logger() { }
public void LogMessage() {
//Open File "log.txt"
//Write Message
//Close File
}
}
3
Example: Logger (cont)
• Since there is an external Shared Resource
(“log.txt”), we want to closely control how we
communicate with it.
• We shouldn’t have to create the Logger class
every time we want to access this Shared
Resource. Is there any reason to?
• We need ONE.
4
Singleton
• GoF Definition: “The Singleton Pattern ensures a
class has only one instance, and provides a global
point of access to it.”
• Best Uses
– Logging
– Caches
– Registry Settings
– Access External Resources
• Printer
• Device Driver
• Database
03/27/2020 5
5
Logger – as a Singleton
public class Logger
{
private Logger{}
private static Logger uniqueInstance;
public static Logger getInstance()
{
if (uniqueInstance == null)
uniqueInstance = new Logger();
return uniqueInstance;
}
} Note the
parameterless
constructor
03/27/2020 6
6
Lazy Instantiation
• Objects are only created when it is needed
• Helps control that we’ve created the Singleton just once.
• If it is resource intensive to set up, we want to do it once.
03/27/2020 7
7
Singleton vs. Static Variables
• What if we had not created a Singleton for the Logger class??
• Let’s pretend the Logger() constructor did a lot of setup.
In our main program file, we had this code:
public static Logger MyGlobalLogger = new Logger();
• All of the Logger setup will occur regardless if we ever need to log or not.
8
public class Singleton What would happen if two Threading
{ different threads accessed
private Singleton() {} this line at the same time?
private static Singleton uniqueInstance;
public static Singleton getInstance()
{
if (uniqueInstance == null)
uniqueInstance = new Singleton();
return uniqueInstance;
}
}
03/27/2020 9
9
Option #1: Simple Locking
public class Singleton
{
private Singleton() {}
private static Singleton uniqueInstance;
public static Singleton getInstance()
{
synchronized(Singleton.class) {
if (uniqueInstance == null)
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
10
Option #2 – Double-Checked Locking
public class Singleton
{
private Singleton() {}
private volatile static Singleton uniqueInstance;
public static Singleton getInstance()
{
if (uniqueInstance == null) {
synchronized(Singleton.class) {
if (uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
}
11
Option #3: “Eager” Initialization
public class Singleton
{
private Singleton() {} pg 181
private static Singleton uniqueInstance = new Singleton()
public static Singleton getInstance()
{
return uniqueInstance;
Runtime guarantees
}
that this is thread-
} safe
1. Instance is created the first time any
member of the class is referenced.
2. Good to use if the application always
creates; and if little overhead to create.
03/27/2020 12
12
Lab #1: Turn a class into a Singleton
public class Logger {
public Logger() { }
public void WriteLine(string text) { }
public string ReadEntireLog()
{
return “Log Entries Here”;
}
}
Take this class and turn it into a Singleton.
03/27/2020 13
13
Lab #1 Answer
public class Logger
{
private Logger() { }
private static Logger instance;
public static Logger getInstance()
{
if (instance == null)
instance = new Logger();
return instance;
}
//Functions
. . .
14
public class BaseSingleton {
Lab #2
private BaseSingleton() { }
private static BaseSingleton instance;
public static BaseSingleton getInstance()
{
if (instance == null) {
instance = new BaseSingleton();
}
return instance;
}
//Some state variables
protected int someInt;
//Function is marked as virtual so that it can be overidden
public void DoSomething() {
someInt = 1;
}
}
03/27/2020 15
Lab #2 (cont)
public class SubClassSingleton extends BaseSingleton
{
private SubClassSingleton() { }
public void DoSomething()
{
someInt = 2;
}
public void NewFunction() {
//new functionality here
}
}
03/27/2020 16
Lab #2 (cont)
• Question #1: What is wrong with the constructor for
SubClassSingleton?
03/27/2020 17
Lab #2 (cont)
Here is the code that calls the Singleton:
public class Main
{
public static void DoStuff()
{
01 BaseSingleton.getInstance().DoSomething();
02 SubClassSingleton.getInstance().DoSomething();
03 SubClassSingleton.getInstance().NewFunction();
03/27/2020 18
Lab #2 (cont)
Question #2: For Line 01, what is the value of someInt
after it is called?
Question #3: For Line 02, what is the value of someInt
after it is called?
Question #4: What is wrong with Line 03?
03/27/2020 19
Lab #2 Answers
Question #1 : It will not compile. The base constructor
must be changed from private to protected.
Question #2 – 1
Question #3 - 1
– Even though we have overridden the base, it doesn’t matter.
The base implementation is returned by getInstance().
Question 4 – It will not compile!
20
• Pattern Name – Singleton SUMMARY
• Problem – Ensures one instance of an object and global access to it.
• Solution
– Hide the constructor
– Use static method to return one instance of the object
• Consequences
– Lazy Instantiation
– Threading
– Inheritance issues
– Hides dependencies
– Difficult unit testing
03/27/2020 21
21
Credits
Jon Simon
jonathan_simon@yahoo.com