클래스에 하나의 인스턴스만 있고, 그 인스턴스에 대한 전역 접근 지점을 제공하는 생성 패턴
싱글턴 패턴 - 한 번에 두 가지의 문제를 해결하며 SRP를 위반함
최근에는 싱글턴 패턴이 대중화돼서 위의 두 문제 중 하나만 해결해도 싱글톤이라고 부를 수 있음
모든 싱글턴의 구현은 공통적으로 아래 두 단계를 거침:
new 연산자 쓰는 것 방지코드가 싱글턴 클래스에 접근할 수 있으면 싱글톤 정적 메서드 호출 가능 → 해당 메서드가 호출될 때마다 항상 같은 객체 반환

getInstance 선언getInstance 메서드를 호출하는 게 싱글턴 객체를 받아오는 유일한 방법이여야 함- e.g. 프로그램의 여러 부분에서 공유되는 하나의 데이터베이스 객체
- 싱글턴 패턴은 특별한 생성 메서드를 제외한 클래스의 모든 객체 생성 방법을 비활성화함
→ 생성 메서드는 새 객체를 생성하거나, 이미 생성되었다면 기존 객체를 반환
- 전역 변수와 다르게 싱글턴 패턴은 클래스에 하나의 인스턴스만 존재함을 보장,
싱글턴 클래스 자체를 제외하고 그 무엇도 캐시된 인스턴스를 대체할 수 없음
- `getInstance` 본문을 변경해서 싱글턴 인스턴스의 최대 갯수를 임의로 조정할 수 있음
1. 싱글턴 인스턴스를 저장할 클래스에 private 정적 필드 추가
2. 싱글턴 인스턴스를 받아오는 public 정적 생성 메서드 선언
3. 정적 메서드 내부에 “지연된 초기화” 구현
→ 첫 호출에는 새로운 객체를 만들어 정적 필드에 넣고, 이후 호출에는 항상 그 인스턴스를 반환
4. 클래스의 생성자를 private으로 만듦 → 클래스의 정적 메서드는 생성자를 호출할 수 있지만 다른 객체들은 불가능
5. 클라이언트 코드에서 싱글턴 생성자에 대한 직접 호출을 정적 생성 메서드로 변경
- 클래스의 단일 인스턴스 보장
- 해당 인스턴스에 대한 전역 접근 지점 획득
- 싱글턴 객체를 처음 요청받았을 때에만 초기화됨
- SRP 위반 - 두 문제를 한 번에 해결함
- 나쁜 설계를 감출 수 있음 (e.g. 프로그램의 컴포넌트들이 서로에 대해 너무 많이 알고 있는 경우)
- 멀티스레드 환경에서 여러 개의 스레드가 싱글턴 객체를 여러 번 생성하지 않도록 특별 조치 필요
- 많은 테스트 프레임워크는 mock 객체를 생성할 때 상속에 의존하기 때문에 클라이언트 코드의 유닛 테스트가 어려움
- 싱글턴 클래스의 생성자는 private이고 정적 메서드를 override하는 건 대부분 언어에서 불가능하기 때문에
싱글턴을 mock할 창의적인 방법 사용 or 테스트 작성 X or 싱글톤 패턴 사용 X
- 퍼사드 패턴은 대부분 하나의 퍼사드 객체면 충분하기 때문에 싱글턴 패턴으로 변경 가능
- 객체들의 모든 공통 상태를 하나의 플라이웨이트 객체로 줄이면 플라이웨이트 패턴과 싱글톤 패턴이 비슷해지만
두 가지 근본적인 차이점 존재
1. 싱글턴 인스턴스는 하나만 있어야 하지만
플라이웨이트 클래스는 고유 상태가 다른 여러 개의 인스턴스를 가질 수 있음
2. 싱글턴 객체는 변경 가능하지만 플라이웨이트 객체는 변경 불가
- 추상 팩토리, 빌더, 프로토타입 패턴 모두 싱글턴 패턴으로 구현 가능
/**
* The Singleton class defines the `getInstance` method that lets clients access
* the unique singleton instance.
*/
class Singleton {
private static instance: Singleton;
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
private constructor() { }
/**
* The static method that controls the access to the singleton instance.
*
* This implementation let you subclass the Singleton class while keeping
* just one instance of each subclass around.
*/
public static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
/**
* Finally, any singleton should define some business logic, which can be
* executed on its instance.
*/
public someBusinessLogic() {
// ...
}
}
/**
* The client code.
*/
function clientCode() {
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
if (s1 === s2) {
console.log('Singleton works, both variables contain the same instance.');
} else {
console.log('Singleton failed, variables contain different instances.');
}
}
clientCode();
// Output.txt
Singleton works, both variables contain the same instance.
참고 자료: Refactoring.guru