디자인패턴이 공부해 보고싶어서 추천받은 patterns 사이트에서 공부하며 정리해보려 한다.
싱글톤은 1회에 한하여 인스턴스화가 가능하며 전역에서 접근 가능한 클래스를 지칭한다.
만들어진 싱글톤 인스턴스는 앱 전역에서 공유되기 때문에 앱의 전역 상태를 관리하기에 적합하다.
아래는 코드는 patterns에서 설명하는 class문법을 활용한 예시이다.
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())
ES5까진 class 없이 함수로 클래스를 정의했기 때문에 클로저를 사용해서 싱글톤 패턴을 구현해 보면 아래와 같다.
const singletonCounter = (function () {
let instance;
let counter = 0;
init = () => {
return {
getInstance: () => {
return instance;
},
getCount: () => {
return counter;
},
increment: () => {
return ++counter;
},
decrement: () => {
return --counter;
},
};
};
return (instance = Object.freeze(init()));
})();
위 코드에서 instance와 counter를 클로저를 통해 숨기고 Object.freeze를 통해 해당 클래스의 메서드나 프로퍼티를 수정하지 못하도록 했다.
또한 즉시 실행함수로 할당했기 때문에 patterns의 예시에서 Counter 객체로 인스턴스를 한번만 만들게 한것 처럼 위 예제의 인스턴스는 singletonCounter
만이 가지는 유일한 인스턴스이다.
이렇게 싱글톤 패턴으로 인스턴스를 하나만 만들게 한다면 어느 위치에서든 이 인스턴스를 통해 count값을 수정하기 때문에 일관성있게 코드를 작성할 수 있다.
모든 방식엔 장점과 단점이 공존한다.
장점부터 보면
단점으로는
이러한 싱글톤은 전역에서 이 한 인스턴스를 사용하게 해서 전역 상태값에 사용될 수 있을것 처럼 보인다.
아마 바닐라자바스크립트를 통해서 웹 프로젝트를 한다면 이렇게 싱글톤으로 인스턴스를 생성해서 전역 상태값을 관리하는게 좋아보이긴 한다.
하지만 리액트에서는 Redux나 context를 사용하기 때문에 굳이 사용은 안할것 같다.
그 이유는 Redux나 context는 읽기만 가능하고 리스패쳐를 통해 넘긴 액션에 대해서만 상태를 업데이트 할 수 있기 때문에 싱글톤으로 직접 구현해서 사용하는 것 보다 더 일관성있게 구현할 수 있기 때문이다.
자바스크립트에서는 이런 싱글톤 패턴이 안티패턴으로 불린다.
그 이유는 {}이렇게 직접 인스턴스를 만들 수 있기 때문에 굳이 위와같이 싱글톤 객체를 생성해서 사용하는 방식은 오버엔지니어링이기 때문이다.
따라서 만약 바닐라자바스크립트로 프로젝트를 할 경우가 생긴다면 한번 사용해보겠지만 앞으로 사용할 일은 없을것 같다.
참고: https://patterns-dev-kr.github.io/design-patterns/singleton-pattern/