[CS지식] 1-1. 디자인 패턴 - 싱글톤 패턴(Singleton Pattern)

김zunyange·2023년 5월 15일
0

CS Note

목록 보기
1/13
post-thumbnail

면접을 위한 CS 전공지식 노트

나는 전공자가 아니기 때문에 CS 관련 기반 지식이 매우 부족하다. IT 지식 뿐만 아니라 면접이나 포트폴리오 등 지금껏 내가 준비하지 못한 내용들이 이 책에 잘 정리되어있다고 하여 기본기가 탄탄한 개발자가 되기 위해 이 책을 기반으로 CS 전공지식을 정리해보려 한다! 👩🏻‍💻


Chapter 1. 디자인 패턴과 프로그래밍 패러다임

1장에서는 라이브러리나 프레임워크의 기본이 되는 디자인 패턴이나 어떠한 방식으로 로직을 구성해야 하는지에 대한 프로그래밍 패러다임을 배운다.

🪄 여기서 잠깐!
∙ 프레임워크 : 다른 사람이 만들어둔 코드의 정해진 틀(frame) 속에서만 수동적으로 작업 해야 함 (모든 도구가 갖춰진 주방)
∙ 라이브러리 : 개발자가 작업을 진행할 때 필요한 기능을 찾고 능동적으로 가져와서 사용할 수 있음 (🫕🥣🔪용도에 따라 가져다 쓰는 도구)

1-1. Design Pattern

디자인 패턴이란?
프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 '규약' 형태로 만들어 놓은 것

디자인 패턴은 프로그램을 개발하는 과정에서 빈번하게 발생하는 디자인 문제를 정리해서 상황에 따라 간편하게 적용할 수 있게 정리한 것이다. 디자인 패턴을 활용하면 단지 코드만 ‘재사용’하는 것이 아니라, 더 큰 그림을 그리기 위한 디자인도 재사용할 수 있다. 잘 활용만 하면 적지 않은 시간과 노력, 시행착오를 줄일 수 있다.

그렇다면 디자인 패턴 종류에는 뭐가 있을까?

1-1-1. Singleton Pattern

싱글톤 패턴이란?
(싱글톤 패턴은 소프트웨어 디자인 패턴 중 하나로,) 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴

인스턴스란?
인스턴스 = 클래스를 기반으로 생성된 객체
예를 들어, "자동차"라는 클래스가 있다면, 실제로 존재하는 자동차는 클래스를 인스턴스화하여 만든 "인스턴스"

  • 보통 데이터베이스 연결 모듈에 많이 사용된다.
  • 하나의 인스턴스를 만들어 놓고 해당 인스턴스를 다른 모듈들이 공유하며 사용한다.
  • 따라서 인스턴스를 생성할 때 드는 비용이 줄어든다.
  • 싱글톤 패턴을 사용하면 전역 변수를 사용할 때와 마찬가지로 객체 인스턴스를 어디서든지 액세스 할 수 있게 만들 수 있다.
  • 단점은 의존성이 높아진다. -> (6)싱글톤 패턴의 단점에 대해 더 자세한 내용이 있다.

(1) 자바스크립트의 싱글톤 패턴

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


const obj1 = {
    a: 27
}
const obj2 = {
    a: 27
}
console.log(obj1 === obj2) // false

위 코드는 동일한 키와 값을 똑같이 지정했더라도 참조하는 주소값이 다르기 때문에 obj1과 obj2는 각각 유일하게 존재하는 서로 다른 객체이다.

var obj = {
  a: 'hello',
  b: function() {
    alert(this.a);
  }
};

이렇게 객체 리터럴을 사용한 것이 바로 싱글턴 패턴의 대표적인 예지만, 모든 속성이 다 공개되어 있다는 단점이 있기 때문에 비공개로 프로퍼티나 함수를 정의하는 게 제대로 된 싱글톤이다. 그 예시로 아래 코드를 보면,

var singleton = (function() {
  var instance;
  var a = 'hello';
  function initiate() {
    return {
      a: a,
      b: function() {
        alert(a);
      }
    };
  }
  return {
    getInstance: function() {
      if (!instance) {
        instance = initiate();
      }
      return instance;
    }
  }
})();
var first = singleton.getInstance();
var second = singleton.getInstance();

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

IIFE(즉시 실행 함수 표현)로 비공개 변수를 가질 수 있게 만들어준다. 그리고 그 안에 instance변수와 initiate 함수를 만들어준다. initiate 함수 안의 내용이 실제 객체의 내용이다. 위의 obj 객체와 비교하면 a가 비공개 변수가 되었다.

IIFE로 즉시 반환되는 부분(return)을 보면, getInstance라는 메소드를 가진 객체를 반환하는데, getInstance 함수를 호출하는 순간 내부적으로 initiate 함수가 호출되고, instance에 아까 그 객체의 내용이 저장되고 동시에 반환된다. getInstance가 여러 번 호출됐을 경우에는 코드를 보시면 이미 instance 객체가 있는 경우에는 initiate를 거치지 않고 바로 반환하는 것을 알 수 있다.

first와 second 변수를 보면 두 번 다 getInstance 함수를 호출했는데, 결과적으로 두 변수는 같다. first 때 initiate된 객체를 second 때도 똑같이 반환받았기 때문이다. 즉, 아무리 호출해도 기존에 있던 객체는 복사되는 것도 아니고 그냥 그대로 반환된다. 싱글톤 패턴은 모듈 패턴을 변형한 디자인 패턴이다.

싱글톤을 언제 써야할 지 잘 모르겠다구요? 처음 네임스페이스를 만들 때 사용하면 된다! 예를 들어 게임을 만든다고 치면, 게임 객체를 싱글턴으로 만드는 것이다. 게임 내의 모든 것을 감싸고 있는 객체를 말이다. 게임을 실행했을 때 게임은 한 번만 켜져야하기 때문에 싱글톤이 적절하다.

(2) 데이터베이스 연결 모듈

앞서 설명한 싱글톤 패턴은 데이터베이스 연결 모듈에 많이 쓰인다.
여러 객체 생성으로 인해 다수의 클라이언트가 동시에 설정값이 변경되면 문제가 생기기 때문이다.

const URL = 'mongodb://localhost:####'
const createConnection = url => ({"url": url })
class DB {
 constructor(url) {
   if (!DB.instance) {
     DB.instace = createConnection(url)
  }
   return DB.instance
}
 connect(){
   return this.instance
}
}
const a = new DB(URL)
const b = new DB(URL)
console.log(a===b) // true

이런식으로 데이터베이스를 연결하면 DB.instance라는 하나의 인스턴스를 기반으로 a,b 를 만들기 때문에 인스턴스 생성 비용을 아낄 수 있다.

(3) 싱글톤 패턴의 단점

사실 싱글톤 패턴은 장점보다 단점이 훨씬 많다고 한다. 처음에는 단점이 매우 미묘하여 많은 개발자들이 싱글톤 패턴을 잘못 사용하게 된다고 하는데, 이 점을 주의깊게 읽어보자✨

  • 프로그램에서 어떤 시점에서도 그 클래스의 인스턴스는 딱 하나만 존재하도록 보장하는 것이 싱글톤 패턴의 목적인데, 따라서 싱글톤 패턴은 전역 접근이 가능하여 그만큼 부작용도 따른다고 한다.
  • 예를 들어, 프로젝트 내에서 사용자 관리를 해야 하는 상황이라면 사용자 객체가 생성되고 관리되어야 하는데 이 문제를 해결하기 위해 싱글톤 패턴이 사용된다. 하지만 한 번에 오직 한 명의 사용자만 로그인이 가능하다는 단점이 발생한다고 한다.
  • TDD(Test Driven Development)시 독립적인 인스턴스가 필요하지만 만들기 어렵다.
  • 모듈간의 결합이 너무 강해서 완화하기 위해 의존성을 주입해 줄 수 있고 메인 모듈 아래 의존성 주입자를 두며 이를 거쳐 하위 모듈에 의존성을 주입하게 된다. (의존성 주입에 관해서는 아래에)

가장 중요한 단점은 편의성 때문에 투명성을 희생한다는 것이다.
시간이 지날수록 싱글톤 객체에 접근하는 객체를 추적할 수 없게 된다. 그리고, 더 중요한 것은 싱글톤 객체의 프로퍼티를 수정하는 객체들도 추적할 수 없게 된다. 따라서 싱글톤 패턴이 한 번 프로젝트에 사용되기 시작하면, 더 많은 싱글톤 없이 프로젝트를 나아가는 것이 어려워진다고 한다.

그렇다면 싱글톤 패턴을 조금 더 투명하게 사용할 수는 없을까?

(4) 의존성 주입

의존성 주입

싱글톤 객체를 필요로 하는 객체에게 의존성 주입 방식으로 싱글톤 객체를 전달하면 좀 더 투명하게 사용할 수 있다.
클래스의 인터페이스가 자신의 의존성을 설명하게 되기 때문이다. 무슨 말이냐 하면, 클래스가 자신을 생성하기 위해 어떤 객체들을 필요로 하는지 명확하게 보여준다.

위의 그림처럼 메인 모듈이 '직접' 다른 하위 모듈에 대한 의존성을 주기보다는 중간에 의존성 주입자(dependency injector)가 이 부분을 가로채 메인 모듈이 '간접'적으로 의존성을 주입하는 방식이다.
이를 통해 메인 모듈(상위 모듈)은 하위 모듈에 대한 의존성이 떨어지게 된다.


의존성 주입의 장점

  • 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅, 마이그레이션이 수월하다.
  • 낮은 결합도로 변경에 용이하고, 다른 객체와의 협력 관계에 더 집중하게 해준다.
  • 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어 주기 때문에 애플리케이션 의존성 방향이 일관되고, 애플리케이션을 쉽게 추론할 수 있으며, 모듈 간의 관계들이 조금 더 명확해진다.

의존성 주입의 단점

  • 모듈 간의 관계가 더 명확해진다? ➡️ 모듈들이 더욱더 분리되므로 클래스 수가 늘어나 복잡성이 증가된다.
  • 약간의 런타임 패널티가 생기기도 한다.

의존성 주입 원칙

  • 상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 한다.
  • 둘 다 추상화에 의존해야 하며, 이때 추상화는 세부 사항에 의존하지 말아야 한다.

📋마무리

단점이 더 많다고는 하지만, 싱글톤 패턴은 오직 유일한 객체를 통해서만 어떤 리소스에 접근해야 하는 제약이 있는 상황에서 유용하기 때문에 클래스를 사용하는 입장에서 실수로 여러 번 객체 생성을 시도하더라도 내부적으로 오직 하나의 객체만 생성되고 사용되어 동시성 문제를 해결해주는 측면에서 필요할 것이다.


📍 출처
https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS8616098823
https://www.zerocho.com/category/JavaScript/post/57541bef7dfff917002c4e86
https://cheershennah.tistory.com/223
https://bibi6666667.tistory.com/511

📍 참고하면 좋을 사이트
https://injae-kim.github.io/dev/2020/08/06/singleton-pattern-usage.html (예시가 좋음)
https://www.youtube.com/watch?v=lJES5TQTTWE (아무래도 영상이 최고!)

profile
배움은 즐거워 ~(*ૂ❛ᴗ❛*ૂ)

0개의 댓글