상세 컨텐츠

본문 제목

[TS] TypeScript에서 Singleton 패턴 적용하기

Log.Develop/JS&TS

by bluayer 2020. 10. 6. 17:36

본문

서론

최근 코드 상의 여러 문제를 해결하기 위해서 적극적으로 디자인 패턴을 적용하기 시작했다.
작년만 해도 무분별하게 디자인 패턴을 사용해 왔었는데,
지금은 코드를 작성하고 나서 더 좋은 방법이 없었나 고민하는 하는 과정(보통 리팩토링 과정이긴 하다)에서
코드로 인해 발생할 수 있는 문제에 대해 생각한 다음
좋은 방법으로 알고 있는 디자인 패턴을 조금씩 적용해 나아가고 있다.

아무쪼록 최근에 코드를 작성하던 도중 특정 클래스를 살피다,
시스템 전체에서 해당 클래스를 통해 단 하나의 객체 인스턴스 만을 생성하는 것을 강제해야 함을 꺠달았고,
여러 Class에 공통적으로 적용해야 한다는 점을 깨닫게 되었다.
좋은 방법으로 싱글톤 패턴을 떠올리게 되었고, 적용하였다.

 

싱글톤 패턴이란 무엇인가?

From Wikipedia

싱글톤 패턴은 GOF(Gang Of Four)에서 제안된 디자인 패턴 중 하나로,
인스턴스(Instance)가 오직 하나만 생성되어야 하는 케이스에 사용하는 패턴이다.
예를 들면 설정에 대한 내용이 담겨있는 클래스가 바로 인스턴스가 오직 하나만 생성되어야 하는 케이스일 수 있다.
싱글톤 패턴에 대한 내용 자체는 별로 어렵지 않지만,
보통은 동시성(Concurrency)을 고려해줘야 한다.
시스템 전반에서 단 하나의 인스턴스만 사용된다는 것은 당연히 동시에 시스템에서 접근할 수 있다는 뜻이 된다.
‘만약 중간에 해당 객체의 값이 바뀐다면, 다른 스레드에서도 잘 적용될 수 있는가?’와 같은
동시성 문제를 해결할 수 있어야 한다.

안타깝게도, 본 글에서는 이런 동시성에 대해 구체적으로 다루지 않는다.
다만 하단에 참고할 수 있는 링크를 첨부했으니 살펴보면 좋을 것 같다.

그래서 어떻게 적용했는가?

static 키워드를 이용하여 아주 간단하게 구성하였다.

class Simple {
    private static instance: Simple

    private constructor () {
    }
	
    // 메소드 이름은 달라도 상관없다.
    public static getInstance () {
        return this.instance || (this.instance = new this())
    }
}

instance 속성 안에 해당 클래스의 객체(인스턴스)가 있으면 가져오고,

없다면 생성해서 집어넣는 것이다!

 

너무 간단한데 효과적이다!

(참고로, constructor는 private이기 때문에 생성자를 통한 생성이 불가능해진 것이다!)

 

혹시, 생성할 때 파리미터를 넣을 수는 없는가?

상당히 고민이 되었던 부분이다.
우리는 일반적으로 생성자에 parameter를 주고 이를 통해 변수를 초기화하는 과정을 거친다.
하지만 singleton에서는 이런 방식을 취하기 위해서는, 인스턴스를 가져올 때마다 파라미터를 줘야한다.

만약 getInstance 함수에 파라미터를 넣는다면?
끔찍할 것이다!!
매번 인스턴스를 생성하는 것처럼 파라미터를 넣어줘야 한다.
우리는 한 번만 인스턴스를 생성할 것임에도 불구하고 말이다!

내가 선택한 가장 간단한 방법은, 클래스 내의 다른 함수를 통해 해당 파라미터를 주입하는 것이다.
init 함수를 통해 private 변수에 파라미터를 주입하자!

 

class Simple {
    private static instance: Simple
    private a: number

    private constructor () {
    }
    
    // 메소드 이름은 달라도 상관없다.
    init(a: number) {
    	this.a = a
    }
    
	
    // 메소드 이름은 달라도 상관없다.
    public static getInstance () {
        return this.instance || (this.instance = new this())
    }
}
const a = 1

// 이런 식으로 불릴 것이다
const simple = Simple.getInstance()
simple.init(a)


다만, 이 방식의 방식은 init을 빼 먹게 되면 해당 객체를 호출하는 부분에서 문제가 발생할 수 있다.
(찾아보니, 이런 식의 구현이 이뤄지면 싱글톤이라고 보기 어렵다고 한다.)

관련글 더보기

댓글 영역