정의
- 프로그램 전체 관점에서 특정 클래스의 객체를 하나만 생성하고 그 하나의 객체를 여러곳에서 공통으로 사용하도록 하는 패턴
- 해당 패턴은 특히 예외적으로 특정 언어 플랫폼에 따라서 구현법이 달라진다.
목적
- 설정관리자, 로그 관리자, 캐시 관리자처럼 여러 객체를 두어 따로 존재할 필요없이 한 곳에서만 집중 관리가 필요한 경우
- 생성자 호출하여 객체를 여러개 생성하여 필수 설정 내용이 각 객체마다 따로 관리되어 달라진다.
- 프로그램 전체에서 동일한 설정을 요한다면 문제가 된다.
코드
object ConfigManager {
var timeout = 30
fun printConfig() {
println(timeout)
}
}
- 코틀린에서는 보통 object 문법을 활용하여 싱글톤 패턴을 구현한다.
- 코틀린 컴파일러는 Object로 선언된 클래스에 대해 유일한 객체를 저장할 정적 INSTANCE 필드를 생성한다.
- JVM이 초기화시, ConfigManager 객체 하나가 힙에 생성되고 그 객체의 식별값이 방금 생성한 INSTANCE 필드에 저장된다.
- 이후, val a = ConfigManager 같이 접근하면 새로운 객체를 생성하는게 아니라 INSTANCE에 기 저장된 객체 참조값을 읽어 변수 a에 저장한다.
public final class designpattern.ConfigManager {
public static final designpattern.ConfigManager INSTANCE;
private static int timeout;
private designpattern.ConfigManager();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public final int getTimeout();
Code:
0: getstatic #16 // Field timeout:I
3: ireturn
public final void setTimeout(int);
Code:
0: iload_1
1: putstatic #16 // Field timeout:I
4: return
public final void printConfig();
Code:
0: getstatic #16 // Field timeout:I
3: istore_1
4: getstatic #26 // Field java/lang/System.out:Ljava/io/PrintStream;
7: iload_1
8: invokevirtual #31 // Method java/io/PrintStream.println:(I)V
11: return
static {};
Code:
0: new #2 // class designpattern/ConfigManager
3: dup
4: invokespecial #33 // Method "<init>":()V
7: putstatic #36 // Field INSTANCE:Ldesignpattern/ConfigManager;
10: bipush 30
12: putstatic #16 // Field timeout:I
15: return
}
- 위 코드는 코틀린 컴파일러로 첫번째 있던 코드를 컴파일한 클래스 파일이다.
- public static final designpattern.ConfigManager INSTANCE; 선언을 통해 INSTANCE 필드는 외부에서 접근이 가능하면서도
- ConfigManager 클래스 구조에 저장되어 공용으로 쓸 수 있게 하면서 ConfigManager 라는 클래스 타입으로 초기 상태에서는 null로 저장되었다가 초기화 과정에서 실제 싱글톤 객체의 참조값이 저장된다.