싱글톤 패턴을 구현하는 방법

woply·2022년 1월 18일
0

TIL(Today I Learn)

목록 보기
14/31

📖 ✏️

  1. TIL 시리즈에 작성된 글은 '매일 매일 학습한 지식 조각을 메모해 놓은 포스팅'입니다. 공유가 아닌 개인적인 학습 내용 기록을 목적으로 작성되었음을 알려드립니다.
  2. 그 외 시리즈에 작성된 공유 목적의 포스팅은 시간이 날 때마다 별도로 작성하고 있습니다. 주로, TIL 시리즈에 작성된 내용에서 특정 주제를 선정하고, 더 깊이 공부한 후 정리하여 작성합니다.

싱글톤 패턴을 구현하는 방법

싱글톤은 클래스의 인스턴스가 단 하나만 생성되는 것을 보장하는 디자인 패턴이다. 싱글톤의 핵심은 인스턴스가 2개 이상 생성될 수 없는 구조를 만드는 것이다. 다양한 방식으로 싱글톤 패턴을 구현할 수 있다.

가장 간단하면서 완전한 싱글톤 패턴을 소개한다. 싱글톤의 핵심 개념인 하나의 인스턴스를 생성하려면, static을 이용하여 자기 자신을 인스턴스로 가지게 하고, private 생성자를 이용하여 외부에서의 생성을 막는다.

static 타입은 컴파일 단계에서 new SingletonService()를 통해 객체를 생성하고 instatnce에 참조로 넣어 둔다. static은 클래스 레벨에 올라가기 때문에 딱 하나만 존재하게 된다.

private 생성자는 SingletonService 객체의 중복 생성을 막기 위해 사용한다. 생성자를 이용한 직접 생성방식이 불가능하므로, 인스턴스를 조회할 때는 getInstance()를 사용한다. getInstatnce()는 컴파일 시점에서 생성된 인스턴스를 가져다 쓰는 유일한 방법이 된다.

public class SingletonService {

    // 1. static 영역에 객체를 딱 1개만 생성한다.
    private static final SingletonService instance = new SingletonService();

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

    // 3. private 생성자를 선언하여, 외부에서 new 키워드를 사용한 객체 생성을 막는다.
    private SingletonService() {
    }

    public void logic () {
        System.out.println("싱글톤 객체가 가지고 있는 로직 호출");
    }
}

SingletonService 클래스가 싱글톤 패턴을 구현하고 있는지 확인하기 위해서, 객체 생성 테스트를 진행한다. 테스트 결과를 통해 동일한 참조값을 가진 동일한 인스턴스라는 것을 확인할 수 있다.

@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonService() {
    // new SingletonService(); // private 생성자는 new를 이용한 객체 생성이 불가능하다.

    // 서로 다른 2개의 객체 생성
    SingletonService singletonService1 = SingletonService.getInstance();
    SingletonService singletonService2 = SingletonService.getInstance();

    // 객체의 참조값 비교
    System.out.println("singletonService1 = " + singletonService1);
    System.out.println("singletonService2 = " + singletonService2);

    // 객체의 참조값이 동일한지 검증
    assertThat(singletonService1).isSameAs(singletonService2);
}

참고
assertThat을 이용한 검증에 sameequal이 많이 사용된다. 두 메서드의 차이는 아래와 같다.

  • same: 참조값을 비교한다. 자바의 ==과 동일하다.
  • equal: 실제 값을 비교한다. equal은 오버라이드가 가능하다

싱글톤 패턴의 단점도 있다

싱글톤 패턴은 구현에 코드 소모가 큰 편이다. private 생성자, static 타입의 단일 인스턴스 생성, 인스턴스를 호출하는 getInstatnce() 등이 필요하기 때문이다. 또한 테스트하기가 까다롭고, 내부 속성을 변경하거나 초기화 하는 것이 어렵다. 구현체를 직접 다루기 때문에 객체 지향 원칙을 지키지 못할 가능성이 크고, 결과적으로 유연성이 떨어진다.

스프링은 싱글톤 패턴 단점을 해결한다.

스프링 컨테이너의 장점 중 하나는 컨테이너에 등록되는 객체를 모두 싱글톤으로 관리한다는 점이다. 중요한 점은 앞서 언급한 싱글톤 패턴의 단점을 모두 해결한다. 객체 지향 원칙을 충족하면서도 싱글톤의 장점을 활용할 수 있다. 스프링 컨테이너가 자동으로 싱글톤 방식으로 객체를 생성하고 공유하기 때문에 싱글톤 적용을 위해 Bean으로 등록되는 모든 클래스의 코드를 수정할 필요도 없다.

스프링을 이용하면 private 타입의 생성자를 만들고, static 타입의 인스턴스를 미리 만들어두지 않아도 싱글톤을 사용할 수 있다. 이와 같은 스프링의 장점을 통해 빠르고 간편하게 성능 좋은 웹 애플리케이션 개발이 가능하다.


요약

  • 싱글톤은 메모리를 효율적으로 사용하는 장점이 있으나, 여러가지 단점도 존재한다.
  • 스프링은 싱글톤의 단점을 모두 해결하면서, 객체를 싱글톤으로 관리한다.
profile
7년간 마케터로 일했고, 현재는 헤렌에서 백엔드 개발자로 일하고 있습니다. 고객 가치를 설계하는 개발자를 지향하며, 개발, 독서, 글쓰기를 좋아합니다. 업이 심오한 놀이이길 바라는 덕업일치 주의자입니다.

0개의 댓글