치춘짱베리굿나이스
자바스크립트에서의 싱글톤 패턴과 static 본문
자바스크립트에서의 싱글톤 패턴과 static
싱글톤의 의미
Singleton
이름의 ‘Single’ 에서 뭔가 한 개..? 하나의…? 라는 뜻이 연상된다
싱글톤은 특정 클래스에 인스턴스를 단 하나만 생성 (메모리를 단 한 번만 할당) 하여 사용하는 패턴을 의미한다 (= 메모리를 단 한 번만 할당한다)
특징
- 인스턴스가 딱 하나만 생성된다 (대개 private, static 등의 키워드를 이용하여 구현한다)
- ‘단 한 개’ 만 생성되는 인스턴스는 전역으로 참조될 수 있으며, 다른 객체들이 이 공유된 인스턴스에 접근할 수 있어 데이터 공유가 편리하다
- 메모리를 한 번만 할당하면 되기 때문에 효율이 좋다
인스턴스가 ‘단 하나' 임을 보장하고 싶을 때 주로 사용한다
단점
- 일반 클래스보다 더 복잡하며, 비동기적인 상황에서 동시에 인스턴스가 생성될 수 있는 문제 (동시성) 를 해결할 수 있어야 한다
- 테스트가 어렵다
- 전역으로 단 하나만 존재하는 인스턴스이기 때문에, 내부의 속성값이 변하지 않아 테스트를 할 때마다 인스턴스를 초기화해 주어야 한다
- 자식 클래스를 만들 수 없다
- 싱글톤 인스턴스가 너무 많은 업무를 하거나, 외부 객체에 데이터 공유가 잦아질 경우 인스턴스들 간의 결합도가 높아진다
- 이는 ‘개방-폐쇄 원칙’을 위반한다
- 개방 폐쇄 원칙이란: 기존 코드를 변경하지 않으면서 (Close) 기능을 추가 (Open) 할 수 있어야 함을 의미한다
- 객체간 결합도가 높아질 수록, 기존의 의존성 때문에 기능 추가가 어려워질 수밖에 없다
자바스크립트에서 싱글톤 구현해보기
클래스 선언하기
class Singleton {
static #instance;
constructor(name) {
if (Singleton.#instance) {
console.log("Instance already available!!");
return Singleton.#instance;
}
this.name = name;
Singleton.#instance = this;
}
printName() {
console.log(this.name);
}
}
export default Singleton;
정말정말 간단한 클래스를 만들어 보았다
눈에 띄는 부분은 static
키워드인데, 이 키워드를 사용하면 정적 메서드 (정적 프로퍼티) 로써, 인스턴스가 아닌 클래스 자체에 메서드 또는 프로퍼티를 설정해줄 수 있다
test() {
console.log(this.#instance);
}
해당 값을 읽어들이는 메서드를 시도해봤지만,
정적 메서드는 개별 객체가 아닌 클래스에 속한 함수이므로, this 키워드로 읽어들일 수 없다
test() {
console.log(Singleton.#instance);
}
이렇게 클래스 함수의 내부 함수로 호출하면 읽어들일 수 있다
지금은 딱 하나의 인스턴스를 생성한 상태이기 때문에, 해당 인스턴스가 노출되고 있다
console.log(Singleton.#instance);
더불어, private한 프로퍼티로 지정했기 때문에 클래스 내부 (생성자, 메서드 등) 가 아닌 다른 곳에서는 읽어들일 수 없다
static #instance;
constructor(name) {
if (Singleton.#instance) {
console.log("Instance already available!!");
return Singleton.#instance;
}
this.name = name;
Singleton.#instance = this;
}
이처럼 static
키워드를 이용하여 클래스 그 자체에 인스턴스 프로퍼티를 지정하면, 인스턴스가 이미 존재하는지 여부를 생성자에서 판단하는 코드를 작성할 수 있다
- 클래스 내부의 private 프로퍼티 (앞에
#
을 붙인다) 로#instance
를 선언하였다- 아직 값은 할당하지 않고, 클래스 함수가 선언될 시점에 선언만 같이 해준다
- 값 초기화는 첫 번째 인스턴스가 생성되는 시점 (처음으로 생성자가 호출되는 시점) 에 이루어진다
- 생성자는 인자로
name
을 받는다 Singleton.#instance
에 값이 이미 존재한다면, 생성자가 호출된 적이 있고 해당 클래스로 생성된 인스턴스가 존재한다는 의미이므로Singleton.#instance
에 저장된 인스턴스 참조만을 반환한다console.log
는 테스트용으로 출력해 보았다
Singleton.#instance
에 값이 존재하지 않는다면 인스턴스가 생성된 적 없다는 의미이므로, 그 아랫줄로 내려가 인스턴스를 생성한다- 인스턴스의
name
프로퍼티는 인자로 받은name
을 사용한다
- 인스턴스의
- 첫 번째 인스턴스가 생성되었다!
Singleton.#instance
에 해당 인스턴스의 참조 (this
) 를 넣어 초기화해 준다
인스턴스 만들어보기
const singleton1 = new Singleton("babo");
const singleton2 = new Singleton("javascript");
singleton1.printName();
singleton2.printName();
babo
인스턴스와 javascript
인스턴스를 생성하고, printName
메서드를 통해 이름을 출력해 보자
뜨헉
분명 babo
인스턴스와 javascript
인스턴스를 생성해서 둘 다 이름을 출력해 보았는데 어째 이름은 babo
만 출력되고 있다
singleton1
인스턴스가 이미 만들어졌으므로, singleton2
인스턴스는 추가로 생성되지 않고 대신 singleton1
인스턴스의 참조를 반환하기 때문이다
javascript
라는 이름은 아무 의미 없는 값이 되었다
생성자 private하게 만들기
class Singleton {
static #instance;
static #isFromInit;
constructor(name) {
if (!Singleton.#isFromInit)
throw "ConstructorError: Cannot construct new instance from constructor. use Init() instead.";
if (Singleton.#instance) return Singleton.#instance;
this.name = name;
Singleton.#instance = this;
Singleton.#isFromInit = false;
}
static init(name) {
Singleton.#isFromInit = true;
return new Singleton(name);
}
}
export default Singleton;
static 키워드를 응용하여 생성자 함수를 호출하지 않고 외부 함수를 통해야만 인스턴스가 생성되도록 만들 수 있다
- static하고 private한 프로퍼티인
isFromInit
을 선언한다- 이 값은 boolean으로, 후술할
init
함수를 통해서 생성자가 호출되었는지 여부를 검사한다
- 이 값은 boolean으로, 후술할
- 생성자 함수의 최상단에
Singleton.#isFromInit
프로퍼티의 값을 검사하는 조건문을 추가한다init
함수를 통해 생성자가 호출되었으면 이 값이true
일 것이고, 아니면false
또는undefined
일 것이다- 따라서 이 값이
true
일 때만 새로운 인스턴스를 반환할 수 있도록 설정해준 것이다 init
함수를 통해서 호출되지 않았을 경우, 예외를 throw하여 인스턴스가 생성되지 않도록 한다- 인스턴스를 생성하고 나서,
#isFromInit
을false
로 초기화해준다
init
함수를 구성한다Singleton.#isFromInit
을true
로 바꿔주어init
함수로부터 생성자가 호출되었음을 알린다- 생성자를 호출하고 그 인스턴스를 바로 반환한다
const singleton1 = new Singleton("babo");
이렇게 생성자를 바로 거칠 경우 예외가 발생한다
const singleton1 = Singleton.init("babo");
const singleton2 = Singleton.init("javascript");
singleton1.printName();
singleton2.printName();
비단 싱글턴 객체를 만들 때뿐만 아니라, 생성자에 함부로 접근하지 않도록 제한을 주고 싶을 때 응용하면 좋다
기타
자바스크립트도 나름 키워드 구현이 많이 되어있어 간단하게 싱글톤 클래스를 구현할 수 있었다
어떻게 활용할지는? 앞으로 해나가야 할 과제인 듯 하다
참고 자료
[디자인 패턴] 싱글톤 패턴(Singleton Pattern) 정리 및 예제 - 생성 패턴
싱글톤 패턴(Singleton pattern)을 쓰는 이유와 문제점
[Javascript] Singleton Pattern 싱글톤 패턴
'Javascript + Typescript > 이론과 문법' 카테고리의 다른 글
자바스크립트 일반함수 vs 화살표함수 (1) | 2022.08.27 |
---|---|
자바스크립트에서의 Symbol (0) | 2022.08.20 |
Set, Map (0) | 2022.07.30 |
자바스크립트에서의 함수형 프로그래밍 (0) | 2022.07.30 |
자바스크립트에서의 객체지향 (2) 프로토타입 (0) | 2022.07.27 |