The Singleton Pattern
Singleton 패턴은 Creational 패턴들과 같은 그룹에 속하지만, "non-creational" 패턴의 확장적인 면이 있다. 프로그래밍에서 클래스의 인스턴스를 하나만을 갖게 해야 할 경우가 있다. 예를 들어 우리의 시스템은 오직 하나의 윈도우 메니져나 프린트 스풀러를 가질 수 있다.
유일하게 하나의 인스턴스를 갖는 클래스를 만드는 가장 간단한 방법은 static 변수를 클래스에 포함시키는 것이다. static 변수는 유일한 인스턴스의 하나이고, 인스턴스의 수는 문제가 되지 않는다.
static boolean instance_flag = false;
문제는 생성된 인스턴스가 성공적인지 아닌지를 어떻게 찾는가 인데 이것은 생성자가 반환을 하지 않기 때문이다. 한가지 방법은 생성의 성공여부를 체크하는 메소드를 호출하는 것이다. 그리고 메소드들은 static 변수로부터 유도된 값을 반환한다. 이 방법은 세련되지 못하고 오류들을 발생할 수 있는 경향이 있지만, .................................
좀더 나은 방법은 하나 이상 인스턴스가 생성될 때 예외(Exception)를 발생하는 클래스를 생성하는 것이다. 이런 경우에 우리 자신의 예외 클래스를 생성해 보자 :
class SingletonException extends RuntimeException { //new exception type for singleton classes public SingletonException() { super(); } //----------------------------------------------- public SingletonException(String s) { super(s); } }
이 새로운 예외 타입은 특별하게 새로 작성된 내용없이 부모의 클래스를 호출할 것 뿐이다. 그러나 PrintSpooler의 인스턴스를 시도할 때 우리가 잡아야만 하는 예외의 타입을 컴파일러는 우리 자신이 이름을 지은 예외 타입으로 경고하는 편리함이 있다.
Throwing the Exception
PrintSpooler 클래스의 골격을 작성해 보자; 프린팅 메소드들은 생략하고 단지 정확한 Singleton 패턴의 구현에만 초점을 둘 것이다.
class PrintSpooler { //this is a prototype for a printer-spooler class //such that only one instance can ever exist static boolean instance_flag = false; //true if 1 instance public PrintSpooler() throws SingletonException { if (instance_flag) throw new SingletonException("Only one spooler allowed"); else instance_flag = true; //set flag for 1 instance System.out.println("spooler opened"); } //---------------------------------------------- public void finalize() { instance_flag = false; //clear if destroyed } }
Creating an Instance of the Class
지금까지 우리는 PrintSpooler 클래스에서 Singleton 패턴을 생성하였다. 이제 그 것을 어떻게 사용하는 지 알아보자. 예외를 발생시킬 지도 모르는 모든 메소드들에 대하여 try - catch 블럭안에 에워싸야한다는 것을 기억하자.
public class SingleSpooler { public static void main(String[] args) { PrintSpooler pr1, pr2; //open on spooler--this should always work System.out.println("Open one spooler"); try { pr1 = new PrintSpooler(); } catch(SingletonException e) { System.out.println(e.getMessage()); } //try to open another spooler -- should fail System.out.println("Open two spoolers"); try { pr2 = new PrintSpooler(); } catch(SingletonException e) { System.out.println(e.getMessage()); } } }
그리고 나서, 프로그램을 실행시키면 아래와 같은 결과를 얻을 수 있다.
##########0*
Static Classes as Singleton Patterns
표준 자바 라이브러리에는 이미 Singleton 클래스의 종류가 있다:Math 클래스 . 이 클래스는 final로 선언되어 있고 모든 메소들이 static 으로 선언되어 있다. 이는 확장될 수 없음을 의미한다. Math 클래스의 목적은 sin이나 cos 처럼 일반적으로 사용되는 수학적인 함수들을 포장해 놓은 것이다.
우리는 Singleton 클래스를 final 클래스로 하여 Singleton 패턴을 구현할 수 있다. 우리는 Math 클래스 처럼 어떤 인스턴스도 만들 수 없고, final 클래스에 존재하는 static 메소드들을 직접 호출해서만 사용할 수 있다.
final class PrintSpooler { //a static class implementation of Singleton pattern static public void print(String s) { System.out.println(s); } } //============================== public class StaticPrint { public static void main(String argv[]) { PrintSpooler.print("here it is"); } }
final 클래스 접근의 이점중의 하나는 try-catch 블럭을 쓸 필요가 없다는 거다. 이 이점은 만약 우리가 Singleton 상태를 중지하고자 한다면 예외 처리 스타일의 구조보다 더 쉽다는 것이다.
Creating Singleton Using a Static Method
Design Patterns에 제안된 또 하한의 접근은 인스턴스들의 자취를 유지하고 유출하는 static 메소드를 사용하여 Singleton을 생성하는 것이다. 하나 이상의 인스턴스가 만들어 지는 것을 막기 위해 그 클래스의 static 메소드에서만 생성될 수 있는 private 의 생성자를 만든다.
class iSpooler { //this is a prototype for a printer-spooler class //such that only one instance can ever exist static boolean instance_flag = false; //true if 1 instance private iSpooler() { } static public iSpooler Instance() { if (! instance_flag) { instance_flag = true; return new iSpooler(); } else return null; } //------------------------------------------- public void finalize() { instance_flag = false; } }
이렇게 함으로써 얻는 주요 이점은 singleton이 이미 존재한다면 예외처리에 대해서는 신경 쓰지 않아도 된다는 것이다. 또, iSpooler 클래스의 인스턴스를 만드려 한다면 생성자가 private로 선언되어 있어 컴파일시 실패하게 될 것이다.
Other Consequences of the Singleton Pattern
- Singleton을 하위 클래스로 만드는 것은 어려울 수 있는데, 이것은 상위의 Singleton 클래스가 생성되지 않았을 때만 작동하기 때문이다.
- 우리는 적당하고 의미있는 곳에서의 작은 수의 인스턴스를 허용하는 Singleton으로 쉽게 바꿀 수 있다.
'Development > 패턴자료' 카테고리의 다른 글
[펌] The Strategy Pattern (0) | 2011.08.13 |
---|---|
[펌] The State Pattern (0) | 2011.08.13 |
[펌] The Proxy Pattern (0) | 2011.08.13 |
[펌] The Prototype Pattern (0) | 2011.08.13 |
[펌] The Observer Pattern (0) | 2011.08.13 |
안정적인 DNS서비스 DNSEver