생성 패턴 중 하나, 인스턴스를 오직 한 개만 만들어서 제공하는 클래스가 필요한 경우에 사용한다.
생성자(constructor)가 여러 번 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.
주로 공통된 객체를 여러개 생성해서 사용하는 DBCP - DataBase Connection Pool(Prisma와 같은 ORM에서 DB에 다시 연결할 필요 없이 필요할 때마다 요청하여 얻어내는 pool)과 같은 상황에서 사용된다고 한다.
생성자를 클래스 자체에서만 접근할 수 있다.
1.메모리 속도 측면 - 객체의 인스턴스를 재사용(고정된 메모리 영역을 사용하게 된다.)
2. 데이터 공유가 쉽다 - 기존 인스턴스가 전역으로 사용되기 때문
3. 인스턴스가 한개만 존재하는 것을 보장하고 싶을 때.
구현 방법
private constructor -> js에서는 private가 없다.
static method
static 키워드를 통해 클래스 로더가 초기화하는 시점에 정적 바인딩(실행 이전에 값이 확정되는 것)을 통해 해당 인스턴스를 메모리에 등록하기 떄문에 Thread-safe(여러 스레드로부터 동시에 접근이 이루어져도 프로그램 실행에 문제가 없는 것)하다.
class Sample {
static instance = new Sample();
getInstance() {
return instance;
}
}
장점: Thread-Safe -> 다수의 스레드가 동시에 접근하더라도 프로그램의 실행에 문제가 없는 것을 의미한다.
단점: 인스턴스를 미리 만들어 둬서 사용하지 않으면 메모리 측면에서 손해
인스턴스를 실제 사용하는 시점에서 생성하는 방법 - 동적 바인딩(실행 이후에 값이 확정)
class Sample {
static getInstance() {
if(!this.instance) {
this.instance = new Sample();
}
return this.instance;
}
}
장점: 이른 초기화 방법보다 메모리 측면에서 효율적
단점: getInstance()는 멀티 스레드 환경에서 안전하지 않다. - 두 스레드가 동시에 인스턴스에 접근시 인스턴스가 생성되어 있지 않은것을 보고 중복으로 생성할 수 있기 때문.
static을 사용하게되면 모든 인스턴스가 해당하는 변수를 공유하게 된다.
그렇기 때문에 싱글톤 패턴에서는 static ~{ this.instance = new Sample()}을 모든 인스턴스가 공유하게 된다.
모든 인스턴스가 공유하기 때문에 새롭게 메모리를 재할당할 필요가 없어져 효율적이다.
static과 다르게 변수에 접근할 때마다 새롭게 메모리에 추가하여 사용하게 된다.(모든 인스턴스가 공유 X , 각 인스턴스가 사용할 수 있는 별개의 값들로 나누어짐)
모든 인스턴스가 공유하지 않기때문에 다수의 메모리가 필요한 프로그래밍에 적합하다.
-> 특정 게임 방이 여러개 필요할 때 저마다 다른 값을 가져야하기 떄문에 적합
위쪽에서 언급한 이른 초기화나 늦은 초기화에서 나오는 개념인 Thread-safe의 경우에는 다수의 스레드가 접근할 수 있는 경우에 대한 가능성에 대해서 언급을 하지만, js와 같은 단일 스레드에서는 이러한 문제점을 고려할 필요가 없다.
인스턴스 변수나 클래스 변수는 모두 스코프가 클래스 쪽에 있으면서 클래스 내부에서 static이 붙느냐 안붙느냐의 차이로 갈리게 된다.
그렇다면 유저들의 수를 모든 인스턴스에서 공유해야한다고 할 때, 특정 값만 static으로 바꿔서 처리를 할 수 있지 않을까?