[GOF] 싱글톤(Singleton) 패턴
2024. 3. 16. 13:46ㆍ디자인패턴
1. 싱글톤 패턴
- 단 하나의 유일한 객체를 만들기 위한 코드 패턴
- 메모리 절약을 위해, 인스턴스가 필요할때 똑같은 인스턴스를 새로 만들지 않고 재활용 하는 기법
- 대표적으로 데이터베이스 연결 모듈
- 이밖에도 디스크 연결, 네트워크 통신, DBCP 커넥션풀, 스레드풀, 캐시, 로그 기록 등에 이용된다.
- 정적 메소드 getInstance()를 통해 객체를 불러와 변수에 저장하고 이를 출력해보면 똑같은 객체 주소를 가지고있다.
- 객체 하나만 생성하고 여러변수에 불러와도 돌려쓰기를 한것
public class Main {
public static void main(String[] args) {
// Singleton.getInstance() 를 통해 싱글톤 객체를 각기 변수마다 받아와도 똑같은 객체 주소를 가리킴
Singleton i1 = Singleton.getInstance();
Singleton i2 = Singleton.getInstance();
Singleton i3 = Singleton.getInstance();
System.out.println(i1.toString()); // Singleton@1b6d3586
System.out.println(i2.toString()); // Singleton@1b6d3586
System.out.println(i3.toString()); // Singleton@1b6d3586
System.out.println(i1 == i2); // true
}
}
2. 검증된 싱글톤 구현 기법 종류
싱글톤 패턴을 구현하는 기법들은 여러가지 존재하지만, 권장되는 검증된 패턴은 2가지 있다.
- Bill Pugh Solution
- 권장되는 두가지 방법중 하나
- 멀티쓰레드 환경에서 안전하고 Lazy Loading(나중에 객체 생성)도 가능한 완벽한 싱글톤 기법
- 클래스 안에 내부 클래스를(holder)를 두어 JVM의 클래스 로더 매커니즘과 클래스가 로드되는 시점을 이용한 방법
- static 메소드에서는 static 멤버만을 호출할 수 있기 때문에 내부 클래스를 static으로 설정
- 다만 클라이언트가 임의로 싱글톤을 파괴할 수 있다는 단점을 지님 ( Reflection API, 직력화/역직렬화)
class Singleton {
private Singleton() {}
// static 내부 클래스를 이용
// Holder로 만들어, 클래스가 메모리에 로드되지 않고 getInstance 메서드가 호출되어야 로드됨
private static class SingleInstanceHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingleInstanceHolder.INSTANCE;
}
}
- 내부클래스를 static으로 선언하였기 때문에, 싱글톤 클래스가 초기화 되더라도 SingleInstanceHolder 내부 클래스는 메모리에 로드되지 않음
- 어떠한 모듈에서 getInstance() 메소드를 호출할 때, SingleInstanceHolder 내부 클래스의 static 맴버를 가져와 리턴하게 되어 이때 내부 클래스가 한번만 초기화되면서 싱글톤 객체를 최초로 생성 및 리턴하게 된다.
- 마지막 final로 지정함으로서 다시 값이 할당되지 않도록 방지한다.
- Enum 사용
- 권장되는 두가지 방법중 하나
- enum은 애초에 멤버를 만들때 private로 만들고 한번만 초기화 하기 때문에 thread safe함
- enum 내에서 상수뿐만 아니라, 변수나 메소드를 선언해 사용이 가능하기 때문에, 이를 이용해 싱글톤 클래스처럼 응용
enum SingletonEnum {
INSTANCE;
private final Client dbClient;
SingletonEnum() {
dbClient = Database.getClient();
}
public static SingletonEnum getInstance() {
return INSTANCE;
}
public Client getClient() {
return dbClient;
}
}
public class Main {
public static void main(String[] args) {
SingletonEnum singleton = SingletonEnum.getInstance();
singleton.getClient();
}
}
3. 싱글톤 패턴의 단점
- 모듈간 의존성이 높아진다.
- 하나의 싱글톤 클래스를 여러모듈이 공유를 하니깐 인스턴스가 변경되면 참조하는 모듈들도 수정이 필요함
- S.O.L.I.D 원칙에 위배되는 사례가 많다.
- 하나가 여러 책임을 지니는 경우가 많아 단일 책임원칙(SRP)을 위반
- 결합도가 높아지게 되어 개방-페쇠 원칙(OCP)에 위배
- 클라이언트가 추상화가 아닌, 구체 클래스에 의존하게 되어 의존역적 원칙(DIP)도 위반
- 싱글톤 패턴을 객체지향 프로그래밍의 안티 패턴이라고 불리운다.
- TDD 단위 테스트에 애로사항이 있음
하지만, 스프링 컨테이너 같은 프레임워크의 도움을 받으면, 싱글톤 패턴의 문제점들을 보완하면서 장점의 혜택을 누릴 수 있다. ( 싱글톤 컨테이너)
'디자인패턴' 카테고리의 다른 글
[GOF] 추상 팩토리 패턴 (0) | 2024.04.02 |
---|---|
[GOF] 템플릿 메소드 패턴 (0) | 2024.03.19 |
[GOF] 상태(State) 패턴 (0) | 2024.03.18 |
[GOF] 전략(Strategy) 패턴 (0) | 2024.03.17 |