싱글턴은 클래스에 인스턴스가 하나만 있도록 하면서 이 인스턴스에 대한 전역 접근 지점을 제공하는 생성 디자인 패턴이다.

문제

싱글턴 패턴은 단일 책임 원칙을 위반한다.

  1. 클래스에 인스턴스가 하나만 있도록 한다.

    이렇게 사용하는 이유는 공유 리소스(DB 접근 등)에 대한 접근을 제어하기 위함이다. 새 클래스를 만드려해도 이미 만들어진 인스턴스가 반환된다.

  2. 해당 인스턴스에 대한 전역 접근 지점을 제공한다.

    모든 코드가 잠재적으로 전역 변수의 내용을 덮어쓸 수 있고 오류가 발생할 수 있다. 전역 변수와 마찬가지로 싱글턴 패턴을 사용하면 프로그램의 모든 곳에서 접근할 수 있다. 또한 코드가 프로그램 전역에 흩뿌려져있다.

해결책

싱글턴 패턴은 다음 두 단계를 갖는다.

  • 다른 객체들이 싱글턴 클래스와 함께 new 연산자를 사용하지 못하도록 디폴트 생성자를 비공개로 설정한다.
  • 생성자 역할을 하는 정적 메소드를 만든다. 내부적으로 이 메소드는 객체를 만들기 위해 비공개 생성자를 호출 후 객체를 정적 필드에 저장한다. 이 메소드에 대한 그 다음 호출들은 모두 캐시된 객체를 반환한다.

구조

싱글턴 패턴 구조

코드

public class TheSingleton {
    private TheSingleton() {
    }

    public static TheSingleton getInstance() {
        return Instance.INSTANCE;
    }

    public static class Instance {
        public static final TheSingleton INSTANCE = new TheSingleton();
    }
}

언제 사용하는가

싱글턴은 프로그램에서 단일 인스턴스만 있어야 할때 사용해야한다. 예를 들어 단일 데이터베이스 객체가 있다.

싱글턴 패턴은 전역 변수들을 더 엄격하게 제어해야 할 때 사용한다. 싱글턴 패턴은 인스턴스가 하나만 있도록 보장해주기 때문에 싱글턴 클래스 자체를 제외하고 그 어떤 것과도 대체될 수 없다.

장단점

클래스가 하나의 인스턴스만 갖는다는 것을 확신할 수 있다

이 인스턴스에 대한 전역 접근지점을 얻는다

싱글턴 객체는 처음 요청될 때만 초기화된다.

단일 책임 원칙을 위반한다

잘못된 디자인을 가릴 수 있다. (프로그램의 컴포넌트들이 서로에 대해 너무 많이 알고 있을 경우)

다중 스레드 환경에서 여러차례 생성되지 않도록 해야한다.

유닛 테스트가 어려울 수가 있다.

스프링 Bean과의 관계

스프링 Bean은 스프링 컨테이너에서 생성되어 관리된다. 빈을 등록할 때 아무런 설정을 하지않으면 기본적으로 싱글톤 스코프(Scope)로 생성된다. 빈의 인스턴스를 오직 하나만 생성해서 재사용하는 것이다.

싱글톤과의 차이점이라 하면 아무래도 Scope에 있다. 싱글톤은 인스턴스가 생성되고 나면 프로그램이 종료가 될때까지 존재하는 반면 Bean은 Scope를 지정시 지정된 Scope만큼만 살아있기 때문에 엄밀히 말하면 Bean은 싱글톤이라고 말할 수 없다.