ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • private 생성자 또는 enum 타입을 사용해서 싱글톤으로 만들 것
    JAVA/Effective java 2020. 12. 29. 19:35
    • 싱글톤은 흔히 쓰는 용어이다.
    • 하나의 패턴의 이름이고 App을 통틀어서 해당 클래스의 인스턴스가 하나만 사용하는 패턴을싱글톤이라고 한다. 

     

     

    간단하게 싱글톤 패턴을 요약해보면

     

    • 자기 타입에 대한 인스턴스를 private static으로 만들어 놓는다.
    • private 한 생성자를 만든다. 이제 이 타입의 인스턴스는 new를 통해 만들 수 없다.
    • static 한 get메서드를 통해서 이 하나의 인스턴스를 가져다가 쓸 수 있다.

    ( multi-thread 등의 환경을 고려한다면 좀 더 복잡한 형태가 될 것 )

     

     

    • 이처럼 오직 한 인스턴스만 만드는 클래스를 싱글톤이라 부른다.
    • 보통 함수 같은 Stateless 객체 또는 본질적으로 유일한 시스템 컴포넌트를 그렇게 만든다.

     

     

    • 싱글톤의 단점으로는 사용하는 클라이언트 코드를 테스트하는 게 어렵다는 것이다. 
    • 싱글톤이 인터페이스를 구현한게 아니라면 mock으로 교체하는게 어렵기 때문이다.

     

     

    • 싱글톤으로 만드는 방법은 두 가지가 있는데,
    • 두 방법 모두 생성자를 private 으로 만들고 publis static 멤버를 사용해서 유일한 인스턴스를 제공한다.

     

     

    1. 첫번째 방법

     

    • public static final 한 인스턴스를 만들기.

     

    • 이 elevis 라는 인스턴스는 static 이니깐  클래스 로딩 시점에 단 한 번만 초기화되면서 만들어지게 된다.
    • 이 처음 만들어진 인스턴스가 계속 재사용하게 되는 것이다.

     

     

     

    • 리플렉션을 사용해서 private 생성자를 호출하는 방법을 제외하면 (그 방법을 막고자 생성자 안에서 카운팅 하거나 flag를 이용해서 예외를 던지게 할 수도 있지만) 생성자는 오직 최초 한 번만 호출되고 Elvis는 싱글톤이 된다.

     

    생성자 카운팅

    장점

    • 이런 API 사용이 static 팩토리 메소드를 사용하는 방법에 비해 더 명확하고 더 간단하다.

     

     

     

     

     

     

    static 팩토리 메소드


    • 해당 인스턴스를 public이 아닌 private으로 만든다. 
    • 그리고 public으로 싱글톤을 반환하는 팩토리 메서드를 만드는 것.

     

    장점

    • API를 변경하지 않고도 싱글톤으로 쓸지 안 쓸지 변경할 수 있다. 즉 getInstance()를 사용하면 클라이언트의 코드를 변경하지 않아도 된다는 것.
    • 처음엔 싱글톤으로 쓰다가 나중엔 스레드당 새 인스턴스를 만든다는 등 클라이언트 코드를 고치지 않고도 변경할 수 있다.
    • 필요하다면 Generic 싱글톤 팩토리(아이템 30)를 만들 수도 있다.

     

    • static 팩토리 메서드를 Supplier <Elvis>에 대한 메서드 레퍼런스로 사용할 수도 있다.

     

     

    직렬화 (Serialization)


    • 위에서 살펴본 두 방법 모두, 직렬화에 사용한다면 역직렬화 할 때 같은 타입의 인스턴스가 여러 개 생길 수 있다고 한다.
    • 역직렬화 할 때 자바가 내부적으로 호출하는 것이 readResolve()이다
    • 이 readResolve()에서 싱글톤 인스턴스를 리턴하게 해 주면 동일한 인스턴스를 리턴하게 되니 안전하다는 것
    • 모든 인스턴스 필드에 transient를 추가하여 직렬화 하지 않을 수 도 있다.
    1
    2
    3
    private Object readResolve() {
        return INSTANCE;
    }
    cs

     

     

     

    Enum


    • 직렬화/역직렬화 할 때 코딩으로 문제를 해결할 필요도 없고, 리플렉션으로 호출되는 문제도 고민할 필요 없는 방법이 있다.
    • 이 타입에 인스턴스는 여러개를 만들지 않는 이상 INSTANCE 하나인 것이 자명하다.
    •  코드는 좀 익숙치 않아도 싱글톤을 구현하는 최선의 방법이라고 한다.
    • 하지만 이 방법은 Enum 말고 다른 상위 클래스를 상속해야 한다면 사용할 수 없다.
    • (하지만 인터페이스는 구현할 수 있다.)

    참고 자료 


    이펙티브 자바

Designed by Tistory.