티스토리 뷰

발생일: 2009.12.24

문제:
독립적인 기능을 하는 자바스크립트 클래스를 하나 만들었다.
이 클래스를 싱글턴으로 사용하고 싶다.

또한, 일반적인 getInstance() 라는 스태틱 메서드를 사용하는 대신,
바로 생성자를 호출해서 객체를 만들도록(내부적으로 싱글턴 인스턴스를 리턴) 하려고 한다.

어떻게 하면 자바스크립트에서 생성자만으로 싱글턴을 구현할 수 있을까?


해결책:
한참을 고민해봤다.
이런 방법으로 구현해보면 어떨까?

클래스의 생성자에 대한 유효범위를 제한해두고,
그 유효범위 안에서 window 속성의 클래스 생성자(래퍼)를 다시 정의한다.
(일종의 프록시 패턴이라고 할 수도 있겠다)
window 속성의 클래스 생성자에서는 클래스의 유일한 인스턴스를 만들어 리턴하도록 싱글턴을 구현한다.
즉, 외부에서 클래스 생성자를 호출해서 객체를 만들 때에는,
window 속성의 생성자를 호출하게 되므로 생성자만으로 싱글턴을 구현할 수 있다.


아래 실제 구현 예제를 이해하기 위해 몇 가지 자바스크립트 언어에 대한 선수 지식이 필요하다.



간단한 실제 구현 모습은 아래와 같다.

    (function() { // (a) 익명함수로 유효범위를 제한한다.
   
        // (b) window 속성의 생성자를 정의한다.
        // 외부에서 생성자를 호출할 때에는 이 생성자가 호출된다.
        window.Singleton = function(name) {
            // (d) 객체가 생성되어 있지 않을 경우, 새 객체를 _instance 에 담는다.
            if (_instance == null) {
                _instance = new Singleton(name);
            }
            return _instance;
        }
   
        // (c) 유일한 싱글턴 인스턴스
        var _instance = null;
       
        // (e) 실제 객체 생성자
        // 외부에서 이 생성자에 접근할 수 없다.
        var Singleton = function(name) {
            this.name = name;
        }
       
    })();


실제 객체의 생성자는 (e) 부분이다.

외부에서 이 객체의 생성자에 접근하지 못하도록 익명함수(anonymous function)로 생성자를 감싸준다.
이 부분이 (a) 부분이 되겠다.

(c) 와 같이 유일한 싱글턴 인스턴스를 담을 변수를 선언해준다. 전역변수와 같이 선언되어 있지만,
이 변수 역시 생성자와 같은 유효범위에 있기 때문에 외부에서는 접근하지 못한다.

이제 외부에서 이 객체를 생성할 수 있도록 (b)와 같이 window 속성에 같은 이름으로 생성자를 구현해준다.
window.Singleton 은 window 속성이기 때문에 외부에서도 호출이 가능하며,
window prefix 없이 바로 new Singleton() 과 같이 호출이 가능하다.
(외부에서 new Singleton(); 을 호출했을 때 (e) 부분의 실제 함수가 호출되는 게 아니다.)
또한, window.Singleton 객체가 유효범위 밖에서 _instance 를 참조할 수 있는 건, 클로저(closure) 때문이다.

window 속성의 객체 생성자(b)에서는 (d)에서와 같이 싱글턴 부분을 구현한다.
_instance 가 존재하지 않을 경우, 새 객체를 생성해 할당하고, 그렇지 않을 경우 이미 존재하는 객체를 리턴한다.

이와 같이 구현하면 외부에서 new Singleton() 을 호출했을 때,
(실제 객체의 wrapper 격인) window.Singleton() 생성자가 호출되며,
window.Singleton 생성자 내에서 싱글턴 객체를 리턴하게 된다.

아래와 같이 호출해보면, new Singleton() 을 통해 싱글턴 객체가 생성되는 것을 확인할 수 있다.

    // 여기서 호출되는 Singleton 생성자는 window.Singleton 이다.
    var s1 = new Singleton('aaa');
    alert(s1.name); // aaa 출력
   
    var s2 = new Singleton('bbb'); // 이미 생성된 객체가 리턴된다.
    alert(s2.name); // aaa 출력



다소 번거롭긴 하지만, 이 방법을 통해 실제 생성자에 대한 접근을 제한할 수 있고,
new 키워드를 통해 싱글턴 객체를 리턴하도록 구현할 수 있다.
(굳이 패턴으로 나누어 생각하려고 한다면, 싱글턴 + 프록시 패턴 정도겠다. )

일반적인 패턴처럼, getInstance() 를 통해 싱글턴 객체를 생성하고 싶을 경우,
같은 방법으로 익명함수 내에서 window.Singleton 안에 getInstance() 를 정의해주면 되겠다.

기타 다른 방법들도 있지만,
기존 생성된 객체를 유지하는 한도 내에서 유용하게 사용할 수 있을 것이라 생각한다.



* 참고:
검색해보니 싱글턴을 구현하는 다른 방법들에 대한 좋은 자료들이 많다.

    1. How to make a singleton in javascript
이 포스트에서는 static getInstance() 메서드를 통해 싱글턴 객체를 생성하는 방법에 대해 설명되어 있다.
가장 알아보기 쉽고 기본적인 방법이니 참고해보도록 하자.
이 포스트에서는 자바스크립트 모듈 패턴을 통해 싱글턴 객체 생성자를 구현했다.
constructor 이름을 통해 이미 만들어진 객체를 싱글턴으로 만드는 전역 메서드 구현에 대한 방법도 있다.
좋은 내용이 많으니 꼭 읽어보자.
약간 다른 방법. 이 포스트도 참고해보자.


그 외,자바스크립트의 유효범위와 클로저에 대해 잘 이해가 안될 경우, 아래 포스트를 참고하자.
반응형
댓글
공지사항