오늘의 명언
“ 당신은 소프트웨어 품질을 추구할 수도 있고, 포인터 연산을 할 수도 있다. 그러나 두 개를 동시에 할 수는 없다. ”
-
베르트랑 마이어 (Bertrand Meyer)
300x250
싱글톤 패턴이란?
싱글톤(Singleton) 패턴의 정의를 설명해 보자면, 객체의 인스턴스가 단 1개만 생성되는 패턴이다.
이 단일 인스턴스는 프로그램 전체에서 공유될 수 있고, 전역으로 상태를 관리하는데 적합합니다.
싱글톤 패턴을 사용하는 이유?
- 메모리
- 데이터 공유
최초 한번 new 연산자를 통해서 고정된 메모리 영역을 사용하기 때문에 생성된 해당 객체에 접근할 때 메모리 낭비를 방지할 수 있습니다. 이미 1개의 객체 인스턴스를 생성하여 활용하기 때문에 속도 측면에서도 이점이 있습니다. 또 전역으로 상태를 관리하기 때문에 클래스 간에 데이터 공유가 쉽습니다. 하지만 싱글톤 인스턴스가 혼자 너무 많이 사용되거나 많은 클래스들에서 사용하게 되면 클래스들 간의 결합도가 높아져 개방-폐쇄 원칙에서 위배되므로 주의해야 합니다.
ES2015 싱글톤
- 이 클래스는 싱글톤 기준을 충족하지 않습니다. 싱글톤은 한 번만 인스턴스화할 수 있어야 합니다. 하지만 이 클래스는 여러 인스턴스를 생성할 수 있습니다.
- 메서드를 두 번 호출하여 비교해 보면 서로 다른 인스턴스라는 것을 확인할 수 있습니다.
let counter = 0;
class Counter {
getInstance() {
return this;
}
getCount() {
return counter;
}
increment() {
return ++counter;
}
decrement() {
return --counter;
}
}
const counter1 = new Counter();
const counter2 = new Counter();
console.log(counter1.getInstance() === counter2.getInstance()); // 같지 않다
- 위에 코드에서 인스턴스를 하나만 생성할 수 있도록 바꿔보도록 하겠습니다.
- 하나의 인스턴스를 만들기 위한 방법은 instance 변수를 만드는 것입니다. 생성자에서 새 인스턴스가 생성될 때 인스턴스 변수에 이미 값이 있는지 확인하여 새 인스턴스를 만들 때 방지 할 수 있습니다.
let instance;
let counter = 0;
class Counter {
constructor() {
if (instance) {
throw new Error("인스턴스는 하나만 생성 할수 있습니다.");
}
instance = this;
}
getInstance() {
return this;
}
getCount() {return counter}
increment() {return ++counter}
decrement() {return --counter}
}
const counter1 = new Counter();
const counter2 = new Counter();
// Error: 인스턴스는 하나만 생성 할수 있습니다.
- 이 Counter 클래스를 export 하기 전에 Object.freeze 메서드를 사용하면 객체를 사용하는 쪽에서 직접 수정할 수 없게 됩니다. 프로퍼티 추가 및 수정이 불가하므로 인스턴스의 프로퍼티를 덮어쓰는 실수를 예방할 수 있습니다.
let instance
let counter = 0
class Counter {
constructor() {
if (instance) {
throw new Error('You can only create one instance!')
}
instance = this
}
getInstance() {
return this
}
getCount() {return counter}
increment() {return ++counter}
decrement() {return --counter}
}
const singletonCounter = Object.freeze(new Counter()) //freeze 메서드 사용
export default singletonCounter
클로저 싱글톤
- 클로저를 사용해 싱글톤 인스턴스를 구현한 내용입니다.
let HelloSingleton = (function() {
let instance;
let secret = 'screct test';
function init() {
return {
hello: function() {
console.log(secret);
}
}
}
return {
getInstance: function() {
if(!instance) instance = init();
return instance;
}
}
})();
let a = HelloSingleton.getInstance();
let b = HelloSingleton.getInstance();
console.log(a === b); // true
a.foo(); // screct test
ES10(ES2019) 싱글톤
- #을 사용하여 private 필드를 선언할 수 있습니다.
class HelloSingleton {
static #instance;
constructor() {
if(HelloSingleton.#instance) return HelloSingleton.#instance;
HelloSingleton.#instance = this;
}
}
let a = new HelloSingleton();
let b = new HelloSingleton();
console.log(a === b); // true
싱글톤의 단점
위에서 설명한 대로 인스턴스를 하나만 만들도록 하면 메모리 측면에서 많은 이점을 얻을 수 있습니다. 하지만 싱글톤 패턴은 자바스크립트(JavaScript)에서는 거의 사용하지 않는다고 합니다. 그 이유는 JavaScript에서는 클래스를 작성하지 않아도 객체를 만들 수 있기 때문에 싱글톤 패턴을 적용하는 것은 오버 엔지니어링이라고 할 수 있습니다. 어떤 디자인 패턴이건 항상 좋은 패턴만 있는 건 아닙니다. 적절한 순간에 어떻게 사용할지 한번 고민해 보는 것 또한 좋을 거 같습니다.
참조
반응형
잘못된 내용이 있으면 댓글 부탁드립니다. 감사합니다.