클래스가 한 개의 인스턴스만을 만들 수 있도록 하고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴이다.
public class Singleton{
// Singleton 클래스의 유일한 인스턴스를 저장 (private, 외부에서 사용 불가)
// static 변수이므로 객체를 생성하지 않고도 사용 가능
// private이므로 외부에서 사용 불가
private static Singleton uniqueInstance;
// 생성자를 private 형태로 만듦 (Singleton 클래스가 인스턴스화 되지못함)
// 객체 생성을 할 수 없도록 디폴트 생성자 제거 (new Singleton() 불가능)
private Singleton(){ }
// static 메소드이므로 static 멤버 변수 접근 가능
// 객체 생성 가능
public static Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton(); // 객체 생성
}
// 이미 객체를 생성한 경우
return uniqueInstance;
}
}
초콜릿 공장
fill()
drain()
boil()
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
public ChocolateBoiler(){
empty = true; // 보일러가 비어있을 때만 동작
boiled = false;
}
// 채우기
public void fill(){
if(isEmpty()){ // 보일러가 빈 상태
empty = false; // 재료 넣음
boiled = false; // 끓이진 않음
}
}
// 비우기
public void drain(){
if(!isEmpty() && isBoiled()){ // 보일러가 차있고, 다 끓여진 상태
empty = true; // 내용물을 비움
}
}
// 끓이기
public void boil(){
if(!isEmpty() && !isBoiled()){ // 보일러가 차있고, 끓지 않은 상태
boiled = true; // 내용물을 끓인다
}
}
public boolean isEmpty(){
return empty;
}
public boolean isBoiled(){
return boiled;
}
}
: ChocolateBoiler 인스턴스를 하나로 유지하도록 변경
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
// ChocolateBoiler static 객체 생성
private static ChocolateBoiler uniqueInstance;
// public --> private
private ChocolateBoiler(){
empty = true;
boiled = false;
}
// 인스턴스 생성을 위한 static 메소드 정의
public static ChocolateBoiler getInstance(){
if(uniqueInstance == null){
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
// 채우기
public void fill(){
if(isEmpty()){
empty = false;
boiled = false;
}
}
// 비우기
public void drain(){
if(!isEmpty() && !isBoiled()){
empty = true;
}
}
// 끓이기
public void boil(){
if(!isEmpty() && !isBoiled()){
boiled = true;
}
}
public boolean isEmpty(){
return empty;
}
public boolean isBoiled(){
return boiled;
}
}
"항상 인스턴스가 1개만 생성됨"
이 보장되지 않음ChocolateBoiler boiler = ChocolateBoiler.getInstance();
boiler.fill();
boiler.boil();
boiler.drain();
: 여러 쓰레드에서 사용하려고 할 때 locking 메커니즘을 제공해서 한 번에 한 개 쓰레드만 사용할 수 있도록 함
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
public class Singleton {
private static Singleton inst = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return inst;
}
}
public class Singleton {
private volatile static Singleton inst;
private Singleton() { }
public static Singleton getInstance() {
if (inst == null) {
synchronized (Singleton.class) {
if (inst == null) {
inst = new Singleton();
}
}
}
return inst;
}
}
public class Singleton {
// inner static class
private static class InnerSingleton {
static final Singleton inst = new Singleton();
}
private Singleton() { }
public static Singleton getInstance() {
return InnerSingleton.inst;
}
}