Ensures that only one instance of a class is allowed within a system. It is useful to contain a very large read-only object.
5 modes of Singleton Pattern:
- lazy mode: create the object in get method. This will save memory. However, it is not thread-safe (threads may create multiple objects).
- thread-safe lazy mode, low performance: we make getInstance method
synchronized
, but it will reduce performance. (only one thread can get the object at a time) - greedy mode: Eager initialization - create the object when loading the class. Thread-safe, but allocate the memory at very beginning.
```java
public class EagerSingleton {
private static volatile EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
```
- (#6) (best) Thread-safe lazy mode with double check: double-checked locking mechanism - add a
synchronized
block.
```java
public class Singleton() {
private static volatile Singleton instance;
// private constructor,
// prevent from creating instance using `new`
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
```
**Note:** without `volatile`, there is a platform based bug: if the object is very big, initialization will take a long time to finish. Based on different OS, the half baked object will has a reference or doesn't has one yet. If we have the reference to access this half baked object, it throws `LazyInitializationException`.
- Using enum (Java 5 or above):
Enum
is thread-safe and implementation of Singleton by default. However, an enum cannot extends class or implements interfaces.
```java
public enum SingleInstance {
INSTANCE;
private SingleInstance() {}
public void doStuff() { ... }
}
// Use it like this
SingleInstance.INSTANCE.doStuff();
```
- Inner static class initialization. It is lazy loaded, because inner static class is lazy loaded.
```java
public class BillPughSingleton {
private BillPughSingleton() {}
private static class LazyHolder {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return LazyHolder.INSTANCE;
}
} ```
Static fields will use stack memory.
Yes, but serialization will create a deep copy of the object which violates the pattern, so it is not recommended. If we have to implements Serializable
, we have to override readResolve()
so that it returns the instance.
Yes, use reflection api.
java.lang.Runtime
. getRuntime()
is equivalent to getInstance()
.
Throws an Exception from constructor.
Return the same object in readResolve()
. However, a enum singleton is taking cared by JVM by default.
- Type: Object Creational
- JDK usage:
- java.sql.DriverManager#getConnection()
- java.lang.Class#newInstance()
- Keyword: function enhancement.
- Type: Object Structural pattern
- Purpose: Allows for the dynamic wrapping of objects in order to modify their existing responsibilities and behaviors
- JDK usage:
- Java Input/Output API
Thread
class
- Component: this is the wrapper which can have additional responsibilities associated with it at runtime.
- Concrete component: is the original object to which the additional responsibilities are added in program.
- Decorator: this is an abstract class which contains a reference to the component object and also implements the component interface.
- Concrete decorator: it extends the decorator and builds additional functionality on top of the Component class.
- Keyword: clone, shallow copy
- Prototype
- Type: Structural design pattern.
- It is used to make two unrelated interfaces work together.
- JDK usage: Stack.
- Target: It defines the application-specific interface that Client uses directly.
- Adapter: It adapts the interface Adaptee to the Target interface. It’s middle man.
- Adaptee: It defines an existing incompatible interface that needs adapting before using in application.
- Client: It is your application that works with Target interface.
- Type: Behavioral pattern
- Purpose: Lets one or more objects be notified of state changes in other objects within the system.
- Type: Object creation design pattern
- Could be used to solve the problem that construct an object with many optional parameters. (usually we need to overload constructors for all kinds of combinations). E.g. builder for immutable class.
- JDK usage: StringBuilder.