(TIL) 2025-02-11
싱글톤(Singleton)
디자인 패턴 중 하나로, “하나의 객체만 생성” 하는 디자인 패턴이다. 즉, 어떤 클래스가 있으면, 그 클래스의 인스턴스(객체)를 하나만 만들도록 보장하는 방식이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Singleton {
constructor() {
if (!Singleton.instance) {
// instance가 없다면 처음으로 생성
this.value = Math.random(); // 예를 들어 난수 생성
Singleton.instance = this; // 인스턴스를 저장
}
return Singleton.instance; // 항상 동일한 인스턴스를 반환
}
getValue() {
return this.value;
}
}
// 사용 예시
const instance1 = new Singleton(); //첫 번째
const instance2 = new Singleton(); //두 번째
console.log(instance1 === instance2); // true, 둘은 같은 객체!
console.log(instance1.getValue() === instance2.getValue()); // 같은 값
단점
- 전역 상태 관리
싱글톤 객체는 애플리케이션 전역에서 접근할 수 있기 때문에, 상태를 관리하기 어려워진다. 여러 곳에서 같은 객체를 수정할 수 있어, 예기치 않은 버그가 발생할 수 있다. 글로벌 상태를 관리하는 것이 복잡하고 오류를 발생시킬 가능성이 높아진다.
- 단위 테스트 어려움
싱글톤은 전역에서 접근하는 객체이기 때문에, 단위 테스트(Unit Test)가 어려워질 수 있다. 테스트 중에 싱글톤 객체의 상태가 변할 수 있어서, 독립적인 테스트를 작성하는 데 어려움이 있을 수 있다.
의존성 주입(Dependency Injection) 어렵다 싱글톤은 의존성 주입을 어렵게 만듭니다. 의존성 주입을 사용하면 객체 간의 의존 관계를 명확히 하고 테스트를 용이하게 할 수 있지만, 싱글톤을 사용하면 클래스 간의 의존 관계가 숨겨지기 때문에 코드의 유지보수가 힘들어진다.
멀티스레드 환경에서의 문제 발생 가능성
싱글톤 패턴을 멀티스레드 환경에서 사용할 때, 동시에 여러 스레드가 getInstance() 메소드를 호출하면, 인스턴스가 여러 개 생성될 수 있다. 이를 방지하려면 동기화(Synchronization)를 추가해야 하지만, 동기화가 성능에 영향을 미칠 수 있다.
- 유연성 부족
싱글톤은 한 번 인스턴스가 생성되면 고정되기 때문에, 이후에 인스턴스를 변경하거나 교체하는 것이 어렵습니다. 이로 인해 코드가 확장되거나 수정될 때 유연성이 떨어진다.
방안
- 의존성 주입(Dependency Injection)
객체가 필요한 의존성을 외부에서 주입받도록 설계하는 방법이다. 이는 클래스 간의 결합도를 낮추고, 테스트가 용이하며, 코드의 유연성을 높이는 데 도움이 된다.
- 팩토리 패턴(Factory Pattern)
객체 생성 로직을 별도의 클래스나 메소드로 분리하여, 필요할 때마다 객체를 생성하는 방법이다. 이를 통해 객체 생성 로직을 유연하게 관리할 수 있다.
- 전역 상태 최소화
가능한 한 전역 상태를 최소화하고, 객체 간의 의존성을 명확하게 관리하는 것이 중요하다. 이를 위해 여러 디자인 패턴을 활용할 수 있다.
결론
싱글톤 패턴은 하나의 인스턴스를 전역에서 공유해야 할 때 유용하다.
- 애플리케이션의 설정, 로그, 캐시, 리소스 관리 등에서 하나의 인스턴스를 여러 곳에서 재사용해야 할 때
- 상태를 전역적으로 공유해야 할 때
- 단일 진입점이 필요할 때
하지만 상태 관리와 테스트 용이성 등을 고려했을 때, 불필요한 싱글톤 패턴의 사용은 피하는 것이 좋다.