CS

CS | 디자인 패턴 - 싱글톤 패턴

3jun 2022. 7. 30. 01:28

디자인 패턴이란?

프로그램을 설계할 때 발생할 수 있는 문제점들을 객체간의 상호관계 등을 이용하여 해결할 수 있도록 하나의 규약 형태로 만들어 놓은 것

1.1.1 싱글톤 패턴

하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴

장점

  • 하나의 인스턴스를 여러 모듈이 공유하여 사용하기 때문에 인스턴스 생성 시에 드는 비용을 절감할 수 있다.

단점

  • 의존성(또는 종속성)이 높아진다.
  • ⇒ TDD (Test Driven Development) 할 때 걸림돌이 된다. TDD를 할때는 단위 테스트가 서로 독립적 이어야 하며 테스트를 어떤 순서로든 실행시킬 수 있어야 하는데, 싱글톤 패턴에서는 테스트마다 독립적인 인스턴스를 만들기 어렵기 때문

⇒ 이를 해결할 수 있는 것? 의존성 주입, DI (Dependency Injection)

의존성 주입

메인 모듈이 하위 모듈에 직접 의존성을 주입하지 않고 중간에 의존성 주입자(Dependency Injector) 가 이를 가로채 메인 모듈이 간접적으로 의존성을 주입하는 방식 ⇒ 디커플링이 된다.

장점

  • 모듈을 쉽게 교체할 수 있는 구조가 되어 테스팅, 마이그레이션이 용이해진다.
  • 구현 시 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어주기 때문에 애플리케이션 의존성 방향이 일관되고, 쉽게 추론이 가능하고, 모듈 간의 관계가 더 명확해진다.

단점

  • 모듈이 더욱 분리되어 복잡성이 증가할 수 있고 런타임 패널티가 생기기도 한다.

의존성 주입원칙

  1. 상위 모듈은 하위 모듈에서 그 어떤 것도 가져와서는 안된다.
  2. 추상화에 의존해야 한다.
  3. 추상화는 세부사항에 의존해서는 안된다.

자바스크립트에서 싱글톤

리터럴 { } 또는 new Object 로 객체를 생성하게 되면 그 어떤 객체와도 같지 않기 때문에 이것 만으로도 싱글톤 패턴을 구현할 수 있다.

const obj1 = {
  a: 25
}
const obj2 = {
  a: 25
}

console.log(obj1 === obj2) //false

Q. 하나의 클래스에 하나의 인스턴스, But 위 코드를 보면 Object 클래스에 여러 인스턴스 아닌가?

console.log(obj1.a === obj2.a) //true

obj1.a = 2;
console.log(obj1.a === obj2.a) // false
console.log(obj1.a, obj2.a) // 2, 25

obj1, obj2 는 독립적인 인스턴스이지 않는가?

class Singleton {
	constructor() {
		if(!Singleton.instance) {
			Singleton.instance = this;
		}
		return Singleton.instance;
	}

	getInstance() {
		return this.instance;
	}
}

const a = new Singleton();
const b = new Singleton();

console.log(a === b);   // true

Q. new Singletone() 와 new Singletone.getInstance() 의 차이 (왜 false 인가, Singleton.instance === this.instance)

클로저를 활용하여 비공개 멤버를 가진 싱글톤 객체 생성하기

객체 리터럴로는 비공개 상태 및 함수를 정의할 수 없지만, 규모가 큰 라이브러리에서는 흔히 외부에서 접근할 수 없는 비공개 멤버를 가지고 있다.

const Singleton = (function () {

    /**
     * --------------------------------
     * 싱글톤 패턴 구현 코드
     * --------------------------------
     */

    // 비공개 변수, 메서드 정의
    let instantiaed;

    function init() {

        // 싱글톤 객체 정의
        return {
            // 공개 메서드 정의
            publicMethod : function () {
                return 'hello Singleton Pattern!!!';
            },
            // 공개 프로퍼티 정의
            publicProp : 'single value'
        }

    }

    // 공개 메서드인 getInstance() 를 정의한 객체.
    // 렉시컬 특성으로 인해 비공개 변수, 메서드에 접근 가능(클로저)
    return {
        getInstance : function () {
            if (!instantiaed) {
                instantiaed = init();
            }
            return instantiaed;
        }
    }

})();

// 싱글톤 객체 생성하여 publicMethod 호출 가능해짐
var first = Singleton.getInstance();
first.publicMethod();
console.log(first.publicMethod()); // hello Singleton Pattern!!!

var second = Singleton.getInstance();
second.publicMethod();
console.log(second.publicMethod()); // hello Singleton Pattern!!!

console.log(first === second); // true

// 출처: <https://webclub.tistory.com/150> [Web Club:티스토리]

여기서 비공개 함수인 init()의 return 문에서 객체 리터럴로 정의되는 객체가 싱글톤 객체이다.

이 객체는 프로그램 전체에서 하나만 존재한다.

외부에 공개되는 익명함수의 return 문에서는 비공개된 내부 변수 instantiaed 값을 확인하여 싱글톤 객체가 없다면 init() 함수를 호출하여 싱글톤 객체를 생성해서 반환한다.

 

출처
면접을 위한 CS 전공지식 노트 - Section 1.1 디자인패턴
<https://webclub.tistory.com/150> [Web Club:티스토리]