Singleton Pattern

사나이장대산·2024년 11월 13일

Spring

목록 보기
19/26

싱글톤 패턴(Singleton Pattern)

클래스의 인스턴스가 오직 하나만 생성되도록 보장하는 디자인 패턴이다.

  • 싱글톤 패턴의 등장

    • Web Application은 불특정 다수의 고객이 동시에 많은 요청을 보낸다.
  • 요청을 할 때 마다 객체를 새로 생성되고 처리가 완료되면 소멸된다.

  • 메모리 낭비가 아주 심하다.

  • 싱글톤 패턴 적용

    • 객체 인스턴스가 하나만 생성되고 생성된 인스턴스만 사용하도록 만든다.
  • 객체가 한번만 생성되어 리소스를 절약할 수 있다.

  • Java 코드 예시

public interface Singleton {
	void showMessage();
}

public class SingletonImpl implements Singleton {
    private static SingletonImpl instance;

    // private 생성자를 통해 외부에서 객체 생성을 방지
    private SingletonImpl() {}

    // public으로 설정하여 인스턴스가 필요하면
    // getInstance 메서드를 통해 인스턴스에 접근하도록 만듦
    public static SingletonImpl getInstance() {
        // 인스턴스가 없을 때만 생성
        if (instance == null) {
            instance = new SingletonImpl();
        }
        return instance;
    }

    @Override
    public void showMessage() {
        System.out.println(instance.toString());
    }
}
  • 싱글톤 패턴의 문제점
    • 싱글톤 패턴을 구현하기 위한 코드의 양이 많다.
    • 구현 클래스에 의존해야 한다.(DIP, OCP 위반)
    public class MainApp {
    public static void main(String[] args) {
       // 첫 번째 싱글톤 인스턴스 요청, 구현클래스.getInstance();
        Singleton instance1 = SingletonImpl.getInstance();
        instance1.showMessage(); // 인스턴스 주소값 출력

        // 두 번째 싱글톤 인스턴스 요청, 구현클래스.getInstance();
        Singleton instance2 = SingletonImpl.getInstance();
        instance2.showMessage(); // 인스턴스 주소값 출력
        
        // 다른 구현체로 바꾸려면 DIP, OCP 위반
        Singleton instance3 = SingletonImplV2.getInstance();
        instance3.showMessage();
    }
}
  • 유연성이 떨어져서 안티패턴으로 불리기도 한다.
  • Spring의 싱글톤 컨테이너
    - Spring은 Web Application을 만들 때 주로 사용된다.
  • Spring Container는 싱글톤 패턴의 문제점들을 해결하면서 객체를 싱글톤으로 관리한다.
  • Spring Bean은 싱글톤으로 관리되는 객체이다.

Spring이 Bean을 등록하는 방법은 기본적으로 싱글톤 이다. 하지만, 요청할 때 마다 새로운 객체를 생성해서 반환하는 기능도 제공한다.

싱글톤 패턴의 주의점

객체의 인스터스를 하나만 생성하여 공유하는 싱글톤 패턴의 객체는 상태를 유지(statrful)하면 안 된다.

  • 상태 유지(stateful)의 문제점
    • 데이터의 불일치나 동시성 문제가 발생할 수 있다.
    • 코드예시
    public class StatefulSingleton {
    private static StatefulSingleton instance;
    
    // 상태를 나타내는 필드
    private int value;

    // private 생성자
    private StatefulSingleton() {}

    // 싱글톤 인스턴스를 반환하는 메서드
    public static StatefulSingleton getInstance() {
        if (instance == null) {
            instance = new StatefulSingleton();
        }
        return instance;
    }

    // 상태 변경 메서드
    public void setValue(int value) {
        this.value = value;
    }

    // 상태를 반환하는 메서드
    public int getValue() {
        return this.value;
    }
}
public class MainApp {
    public static void main(String[] args) {
        // 클라이언트 1: 싱글톤 인스턴스를 가져와서 상태를 설정
        StatefulSingleton client1 = StatefulSingleton.getInstance();
        client1.setValue(42);
        System.out.println("클라이언트 1이 설정한 값: " + client1.getValue());

        // 클라이언트 2: 동일한 싱글톤 인스턴스를 사용해 상태를 변경
        StatefulSingleton client2 = StatefulSingleton.getInstance();
        client2.setValue(100);
        System.out.println("클라이언트 2가 설정한 값: " + client2.getValue());

        // 클라이언트 1이 다시 값을 확인
        System.out.println("클라이언트 1이 다시 확인한 값: " + client1.getValue());
    }
}
  • 출력 결과
    클라이언트 1이 설정한 값: 42
    클라이언트 2가 설정한 값: 100
    클라이언트 1이 다시 확인한 값: 100
    • value 필드는 공유되는 필드인데, 특정 클라이언트가 값을 변경한다.
    • Spring Bean은 항상 무상태(stateless)로 설계를 해야한다. 아주 중요!
      • 특정 클라이언트에 의존적인 필드가 있거나 변경할 수 있으면 안된다.
profile
사나이 張大山 포기란 없다.

0개의 댓글