Singleton Pattern : 프로그램 라이프사이클 동안 하나의 클래스에 하나의 인스턴스생성만을 허락하는 패턴이다.
Singleton은 개념자체는 복잡하지 않으므로 실질적인 예를 들어 설명하겠다.
/* Singleton.java */
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){ }
public static Singleton getInstance(){
return instance;
}
//멤버변수 및 메소드
}
기본적인 Singleton이다. Singleton으로 구현하고자 하는 클래스의 생성자를 외부에서 접근하지 못하게 하며 자신의 인스턴스 하나를 정적으로 생성해둔다. 그 후 외부에서의 접근은 Singleton.getInstance() 와 같은 접근을 통해 유일한 Singleton 인스턴스를 받아오게된다. 이렇게 외부에서의 생성을 막고 오직 하나의 인스턴스에만 접근하게 하여 Singleton클래스는 두개 이상의 인스턴스가 생성될 수 없게된다.
하지만 static 키워드가 의미하듯 Singleton 인스턴스는 정적인 컴파일시간에 이미 만들어져버리므로 실행중에 다른 처리가 필요하다면 조금 다른 방법이 필요하다.
/* Singleton2.java */
public class Singleton2 {
private static Singleton2 instance = null;
private int randomNumber;
private Singleton2(){}
public static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
Random random = new Random();
instance.randomNumber = random.nextInt(10)+1;
}
return instance;
}
public int getRandomNumber(){ return randomNumber; }
}
Singleton클래스와 비교해보면 Singleton2클래스는 'instance'의 생성을 getInstance() 메소드에서 진행한다. 이러한 생성을 게으른 인스턴스화(Lazy instantiation) 이라고 한다. 만약 Singleton2 클래스를 한번도 생성하지 않는다면 이 클래스에 대한 인스턴스는 하나도 생성되지 않는것이다.
재미있는 부분은 static 메소드인 getInstance() 안에서 non-static 변수나 함수에 접근할 수 없다. 그러므로 'instance'변수를 인스턴스화 한 후 instance.MemberSomthing 와 같은 방법으로 자신의 멤버에 접근해줘야한다. 'instance'는 자기의 멤버이므로 instance의 멤버들은 private멤버에도 접근할 수 있다.
두번째 방법이 훨씬 스마트해보이지만, 멀티스레드환경에선 또다른 문제가 발생한다.
다른 스레드에서 Singleton2.getInstance() 를 동시에 호출하게 될 경우,
if(instance == null){
instance = new Singleton2();
Random random = new Random();
instance.randomNumber = random.nextInt(10)+1;
}
이 루틴이 중복수행될 수 있다. 그럼 Singleton2에 대한 인스턴스가 두개가되버린다.
이를 해결하기 위해 Java가 제공하는 synchronized 기능을 사용할 수 있다.
/* getInstance() method in class Singleton2 ... */
public static synchronized Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
Random random = new Random();
instance.randomNumber = random.nextInt(10)+1;
}
return instance;
}
/* getInstance() method in class Singleton2 ... */
public static Singleton2 getInstance(){
if( instance == null ){
//인스턴스화 직전의 작업만 동기화시킨다.
synchronized(Singleton2.class){
if( instance == null ){
instance = new Singleton2();
Random random = new Random();
instance.randomNumber = random.nextInt(10) + 1;
}
}
}
return instance;
}
'Coding Note' 카테고리의 다른 글
[Design pattern] Prototype (1) | 2013.02.01 |
---|---|
[Design pattern] Builder (0) | 2013.01.31 |
[Design pattern] Factory Method (0) | 2013.01.30 |
[Design pattern] Abstract Factory (0) | 2013.01.27 |
[Design pattern] Observer (4) | 2013.01.22 |