[TIL] 디자인 패턴-싱글톤 패턴

syong·2022년 5월 29일
0

TIL

목록 보기
29/32

❗️230309 수정(version 2)

🤷🏻‍♀️ 디자인 패턴이란?

  • 디자인 패턴이란, 프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 규약 형태로 만들어 놓은 것을 의미한다.
  • 디자인 패턴은 라이브러리와 프레임워크의 기본이 된다.

라이브러리: 공통으로 사용될 수 있는 특정한 기능들을 모듈화한 것. 폴더명, 파일명 등의 규칙이 없고 사용성이 비교적 자유롭다.
내가 작성한 코드가 직접 제어의 흐름을 담당한다면(필요한 객체를 직접 호출하고 가져다 쓰는 것) 그것은 프레임워크가 아니라 라이브러리다.

프레임워크: 공통으로 사용될 수 있는 특정한 기능들을 모듈화한 것. 폴더명, 파일명 등의 규칙이 있으며 라이브러리에 비해 엄격하고 자유도가 낮다.
프레임워크가 내가 작성한 코드를 제어하고, 대신 실행하면(스프링의 경우 스프링 컨테이너가 대신 실행) 그것은 프레임워크가 맞다. (ex. JUnit)

1️⃣ 싱글톤 패턴(Singleton Pattern)

  • 싱글톤 패턴이란, 하나의 클래스에 하나의 인스턴스만 가지는 패턴을 말한다. 주로 데이터베이스 연결 모듈에 많이 사용된다.

자바스크립트 예제코드

class Singleton {
  constructor() {
    if(!Singleton.instance) {
      Singleton.instance = this
    }
    return Singleton.instance
  }
  static getInstance() {
    return this.instance
  }
}
const a = new Singleton();
const b = new Singleton();
console.log(a === b); // true, 인스턴스 참조값 같음

자바 예제코드

public class Singleton {
// 1. static 영역에 객체를 딱 1개만 생성해둔다.(private static final)
private static final Singleton instance = new Singleton();

// 2. public으로 열어서 객체 인스턴스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용한다.
public static Singleton getInstance() {
	return instance;
}

// 3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다. 
private Singleton() {}

// 객체 비교 코드
private Singleton singleton1 = Singleton.getInstance();
private Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2); // true, 인스턴스 참조값 같음

클래스의 생성자(constructor)가 변수 a에 최초로 생성한 instance를 할당하면, 두 번째 변수 b에는 생성자 함수의 조건에 의해 앞서 만들어진 instance와 똑같은 instance를 반환하게 된다. 따라서 a === b는 참이 된다.

싱글톤 패턴의 구현 및 특징

  • 클래스의 생성자를 private으로 보호하여 외부에서 new 키워드로 인스턴스를 생성하지 못하게 한다.
  • 클래스 내부에 static으로 자기 자신의 인스턴스 하나를 생성해두고 이 인스턴스 하나만을 사용한다.
  • 클래스의 인스턴스에 접근하기 위해서는 반드시 클래스 내부의 인스턴스를 반환하는 static 메서드를 통해서만 접근이 가능하며 이 메서드는 항상 같은 인스턴스를 반환하기 때문에 외부 어디에서 접근하더라도 같은 인스턴스를 사용하게 된다.
  • Spring, Nestjs와 같은 프레임워크가 싱글톤 패턴으로 구현되어 있다.

싱글톤 패턴의 단점(이해하지 못한 부분은 기울임 표시)

  • 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다. (내부에서 인스턴스 하나를 생성하는 코드가 반드시 추가되어야 함)
  • 의존관계상 클라이언트 객체가 구체 클래스에 의존한다. DIP를 위반한다.
  • 클라이언트 객체가 구체 클래스에 의존해서 OCP(개방 폐쇄 원칙)를 위반할 가능성이 높다.
  • 내부 속성을 변경하거나 초기화 하기 어렵다.
  • private 생성자로 자식 클래스를 만들기 어렵다. 결론적으로 유연성이 떨어진다.
  • 싱글톤 패턴은 TDD(Test Driven Development)를 할 때 불리하다. TDD를 할 때는 주로 단위 테스트를 진행하는데, 단위 테스트는 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행할 수 있어야 한다. 하지만 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트마다 독립적인 인스턴스를 만들기가 어렵다.
  • 싱글톤 패턴은 모듈 간의 결합을 강하게 만들 수 있다는 단점이 있다. 그렇기 때문에 의존성 주입(Dependency Injection) 을 통해 모듈간의 결합을 느슨하게 만들 수 있다.

위 그림처럼 의존성 주입 전에는 메인 모듈(main module)이 직접 하위 모듈에 대한 의존성을 주고 있지만, 의존성 주입을 하게 되면 중간에 의존성 주입자(dependency injector)가 메인 모듈이 할 의존성 모듈을 가로채 대신 하게 되기 때문에 메인 모듈과 하위 모듈 사이의 의존성이 떨어지게 된다. 이를 디커플링 된다고 표현하기도 한다.

의존성 주입이란?

따로 게시글 첨부 예정..

의존성 주입의 장점

  • 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅하기 쉽고 마이그레이션하기도 수월해진다.
  • 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어 주기 때문에 애플리케이션 의존성 방향이 일관되고, 애플리케이션을 쉽게 추론할 수 있으며, 모듈 간의 관계들이 조금 더 명확해진다. -> 싱글톤 패턴은 의존관계상 구체클래스에 의존하게 되는데(DIP 위반), 의존성 주입을 하게 되면 이러한 싱글톤 패턴의 단점을 해결할 수 있다.

의존성 주입의 단점

  • 모듈들이 더욱더 분리되므로 클래스 수가 늘어나 복잡성이 증가될 수 있으며 약간의 런타임 페널티가 생기기도 한다.

의존성 주입 원칙

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

참고 자료: 면접을 위한 CS 전공지식 노트, 스프링 핵심원리 기본편 강의 자료

0개의 댓글