📗 Computer Science/Design Pattern

📗[CS/DesignPattern] 01. 싱글톤 패턴

혜덕hyeduck 2024. 5. 6. 19:27
💡 용어
  • 라이브러리
    • 공통으로 사용될 수 있는 특정 기능들을 모듈화한 것.
    • 프레임워크에 비해 규칙에 있어 자유롭다.
  • 프레임워크
    • 공통으로 사용될 수 있는 특정 기능들을 모듈화한 것.
    • 라이브러리에 비해 규칙이 좀 더 엄격하다.

디자인 패턴이란?

  • 프로그랜 설계 시 직면한 문제들에 대해 객체 간 상호 관계들을 사용하여 해결할 수 있도록 정의한 일정의 규약

싱글톤 패턴

  • 싱글톤 패턴(Singleton Pattern)이란 ?
    • 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
    • 보통 데이터베이스 연결 모듈에서 많이 사용한다.
    • 장점 : 인스턴스 생성 시 드는 비용이 줄어듦.
    • 단점 : 의존성이 높아짐 → TDD 할 때 문제
      • 보완 방법 → “의존성 주입 (DI, Dependency Injection)
        • 중간에 의존성 주입자(dependency injector)를 통해 메인 모듈이 하위 모듈에 간접적으로 의존성을 주입할 수 있게 한다.
        • 원칙 → “상위 모듈은 하위 모듈에서 어떠한 것도 가져올 수 없으며, 둘 다 추상화에 의존해야 한다.”
        • 장점 : 테스팅, 마이그레이션이 수월. 구현시 추상화 레이어를 기반으로 구현체를 넣어주기 때문에 의존성 방향이 일관되며, 추론이 쉽다.
        • 단점 : 클래스 수가 늘어나 복잡성이 증가될 수 있음, 런타임 페널티.
  • Java 코드로 Singleton 구현하기
    • private 생성자만 정의하여 외부 클래스로부터 인스턴스 생성 차단
    • 싱글톤을 구현하는 클래스 내부 멤버 변수로 private static 객체 변수를 만들 것
    • public static 메소드를 통해 외부에서 싱글톤 인스턴스에 접근할 수 있도록 함
    • Java 코드로 Singleton 구현하기
        • private 생성자만 정의하여 외부 클래스로부터 인스턴스 생성 차단
        • 싱글톤을 구현하는 클래스 내부 멤버 변수로 private static 객체 변수를 만들 것
        • public static 메소드를 통해 외부에서 싱글톤 인스턴스에 접근할 수 있도록 함
        • 방법 1. 단순 메서드 호출
          ⇒ 그러나 멀티 스레드 환경에서 순차적으로 객체 생성이 안 이뤄질 수가 있다.
      public class Singleton {
          private static Singleton instance;
      
          private Singleton() {}
      
          public static Singleton getInstance() {
              if (instance == null) {
                  instance = new Singleton();
              }
              return instance;
          }
      }
      • 방법 2. Synchronized
        ⇒ 1번 방법 보완을 위해 Synchronized 키워드로 잠금 ⇒ 즉, 최초 접근한 스레드가 getInstance() 메서드 호출시 접근하지 못하도록 lock을 걸어둔다. 그러나 이는 성능 저하 문제가 생길 수 있다.
        public class Singleton {
            private static Singleton instance;
        
            private Singleton() {}
        
            public static synchronized Singleton getInstance() {
                if (instance == null) {
                    instance = new Singleton();
                }
                return instance;
            }
        }
      • 방법 3. Static(정적 멤버)
        ⇒ 2번 문제 해결을 위해 등장. JVM 클래스 로딩과 동시에 싱글톤 인스턴스 생성. 그러나 필요없는 경우에도 호출하여 자원 낭비가 발생.
        public class Singleton {
            private static final Singleton instance = new Singleton();
        
            private Singleton() {}
        
            public static synchronized Singleton getInstance() {
                return instance;
            }
        }​
      • 방법 4. Static(정적멤버) + Lazy Holder(중첩 클래스) 
        ⇒ 보편적인 방법, 모듈이 필요한 경우에만 정적 멤버로 선언 → 자원 낭비 문제 해결
        class Singleton {
            private static class singleInstanceHolder {
                private static final Singleton ISTANCE = new Singleton();
            }
        
            public static Singleton getInstance() {
                return singleInstanceHolder.ISTANCE;
            }
        }
        
        // main에서 singleton.getInstance()로 호출
        ​
      • 그외 3가지 방법이 더 존재함 → 추후 공부후 추가 예정