싱글톤 패턴

김멉덥·2022년 8월 13일
0

기술면접 공부

목록 보기
2/8
post-thumbnail

싱글톤 패턴에 대해서 설명해주세요

Backend-Interview-Question

Singleton 패턴이란?

  • 객체(인스턴스)가 딱 하나만 만들어져야 할 때 사용하면 유용한 패턴이다.
  • 이렇게 하나만 생성된 객체를 어디에서든지 참조할 수 있도록 하는 패턴이다.
  • 인스턴스가 필요할 때, 똑같은 인스턴스를 만들지 않고 기존의 인스턴스를 활용하기 위해 사용한다.
  • private 생성자를 가지는 특징이 있으며, 생성된 싱글톤 오브젝트는 저장할 수 있는 자신과 같은 타입의 static 필드를 정의한다.
    • 즉, 클래스 내부에 static 메서드를 통하여 객체를 생성한다.
public class Singleton {
    private static Singleton singleton = null;

    private Singleton(){}

    public static Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

privatestatic

  • 생성자 private 을 사용하기 때문에 → 외부에서 new 로 객체 생성이 불가하다.
    • 매번 새롭게 객체를 생성하지 못하도록 한다.
  • static 이 붙은 클래스 / 메서드 → 정적공간, 메모리 용량이 딱 정해져있다.
    • static이 아닌 것들은 객체가 생성될 때마다 메모리를 차지하지만 static 으로 선언되면 객체가 얼마나 만들어지던 메모리에 지정된 공간에 하나씩만 존재하게 된다.

싱글톤 패턴의 장점

  • 인스턴스를 한개만 가져갔을 때 가지는 장점들이 싱글톤 패턴의 장점이다.
  1. 메모리 측면의 장점
    • 최초 한번의 new 연산자를 통해서 고정된 메모리 영역을 사용하기 때문에 추후 해당 객체에 접근할 때 메모리 낭비를 방지할 수 있다.
    • 이미 생성된 인스턴스를 활용하게 되므로 속도 측면에서도 장점이 존재한다.
  2. 클래스와 클래스 간의 데이터 공유가 용이함
    • 싱글톤 인스턴스가 전역으로 사용되는 인스턴스 이므로 다른 클래스의 인스턴스들이 쉽게 접근할 수 있다.
    • 그러나 동시성 문제 발생의 위험이 있다.

싱글톤 패턴의 문제점

  • 의존 관계상 클라이언트가 구체 클래스에 의존한다.
    • new 키워드를 직접 사용하여 클래스 안에서 객체를 생성하고 있으므로, 이는 SOLID 원칙 중 DIP를 위반하게 되고 OCP 원칙 또한 위반할 가능성이 높다.
      • 객체 지향의 5가지 원칙 (참고)
        1. SRP - 단일 책임의 원칙
          객체는 오직 하나의 책임을 가져야 하는 원칙
        2. OCP - 개방-패쇄 원칙
          객체는 확장에 대해서는 개방적이고, 수정에 대해서는 패쇄적이어야 한다.
        3. LSP - 리스코프 치환의 원칙
          자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있다는 원칙
        4. ISP - 인터페이스 분리의 원칙
          클라이언트에서 사용하지 않는 메서드는 사용해서는 안되므로 인터페이스를 작게 나누어 만들어야 하는 원칙
        5. DIP - 의존성 역전의 원칙
          추상성이 높고 안정적인 고수준의 클래스는 구체적이고 불안정한 저수준의 클래스에 의존해서는 안된다는 원칙
  • private 생성자 때문에 테스트가 번거롭다.
    • 싱글톤 인스턴스는 자원을 공유하고 있기 때문에 테스트가 결정적으로 격리된 환경에서 수행되려면 매번 인스턴스의 상태를 초기화시켜주어야 한다.
    • 그렇지 않으면 어플리케이션 전역에서 상태를 공유하기 때문에 테스트가 온전하게 수행되지 못한다.
  • 멀티스레드 환경에서 동기화 처리를 하지 않았을 때, 인스턴스가 2개가 생성되는 문제도 발생할 수 있다.

멀티스레드 환경에서 안전한 싱글톤 만드는 법

1. Lazy Initialization (게으른 초기화)

public class Singleton {
    private Singleton(){}

    public static Singleton getInstance(){
        return LazyHolder.INSTANCE;
    }

	private static class LazyHolder {
 		public static final Singleton INSTANCE = new Singleton();
    }
}
  • private static으로 인스턴스 변수 만들기
  • private으로 생성자를 만들어 외부에서의 생성을 막음
  • ✔️ 그러나 불필요한 경우에도 인스턴스가 생성되므로 리소스가 낭비됨

2. Lazy Initialization + Double-checked Locking

1번의 성능저하를 완화시키는 방법

public class Singleton {
    private Singleton(){}

    public static Singleton getInstance(){
        return LazyHolder.INSTANCE;
    }

	private static class LazyHolder {
 		public static final Singleton INSTANCE = new Singleton();
    }
}
  • 1번과는 달리, 먼저 조건문으로 인스턴스의 존재 여부를 확인한 다음 두번째 조건문에서 synchronized를 통해 동기화를 시켜 인스턴스를 생성하는 방법
  • 스레드를 안전하게 만들면서, 처음 생성 이후에는 synchronized를 실행하지 않기 때문에 성능저하 완화가 가능함
  • ✔️ 하지만, 여전히 성능 저하의 문제와 함께 완벽한 방법은 아님

3. Initialization on demand holder idiom (holder에 의한 초기화)

클래스 안에 클래스(holder)를 두어 JVM의 클래스 로더 매커니즘과 클래스가 로드되는 시점을 이용한 방법

public class Singleton {
    private Singleton(){}

    public static Singleton getInstance(){
        return LazyHolder.INSTANCE;
    }

	private static class LazyHolder {
 		public static final Singleton INSTANCE = new Singleton();
    }
}
  • 2번처럼 동기화를 사용하지 않는 방법을 안하는 이유는, 개발자가 직접 동기화 문제에 대한 코드를 작성하면서 회피하려고 하면 프로그램 구조가 그만큼 복잡해지고 비용 문제가 발생할 수 있다.
    또한 코드 자체가 정확하지 못할 때도 많다.
  • 이 때문에, 3번과 같은 방식으로 JVM의 클래스 초기화 과정에서 보장되는 원자적 특성을 이용해 싱글톤의 초기화 문제에 대한 책임을 JVM에게 떠넘기는 걸 활용한다.
  • 클래스 안에 선언한 클래스인 holder에서 선언된 인스턴스는 static이기 때문에 클래스 로딩시점에서 한번만 호출된다.
  • 또한 final을 사용해서 다시 값이 할당되지 않도록 만드는 방식이다.
  • ✔️ 실제로 가장 많이 사용되는 일반적인 싱글톤 클래스 사용 방법 !!

사용 예시

  • ex) 다크모드 설정

    사용자가 어떠한 페이지에서 다크모드를 설정하면 다른 모든 페이지에서도 다크모드로 나와야한다.

  • 이 다크모드 설정을 관리하는 객체는 반드시 모든 페이지에서 하나의 같은 것으로 사용해야 한다.
  • 즉, 다크모드를 설정하는 페이지 외의 다른 페이지에서 매번 new다크모드를 설정해주는 객체를 생성하지 않아도 되도록 하기 위해 싱글톤 패턴을 사용한다.

예시상황에 singleton 패턴 적용

  • static 으로 정적 변수에 저장된 값을 다른 페이지에서 그대로 가져다 쓰게하여 매번 new로 다크모드를 설정해주는 객체를 생성하지 않아도 계속해서 변수 값을 불러와 일정한 설정 유지 가능
  • 예시 설명 (with 코드)
    객체지향 디자인패턴 1

참고 자료

싱글톤(Singleton) 패턴이란?
[JAVA] 싱글톤 패턴(Singleton Pattern) : 멀티 스레드 환경에서의 문제점
싱글톤 패턴(Singleton pattern) | 👨🏻‍💻 Tech Interview
2. 싱글톤 패턴(Singleton Pattern)
객체지향 디자인패턴 1

profile
데굴데굴

0개의 댓글