ITEM.3 private 생성자나 열거 타입으로 싱글턴임을 보증하라

Jaeho Kim·2022년 6월 3일
0

이펙티브자바

목록 보기
3/5

싱글턴이란 어플맄케이션 내에 그 클래스의 객체가 단 하나만 만들어지도록 강제하는 방법!

싱글턴을 3가지 만드는 방법 !

final 필드

  • 생성자를 private으로 막아두고 final 필드로 인스턴스를 제공
public class Singleton1 {

    public static final Singleton1 INSTANCE = new Singleton1();

    private Singleton1() {}
}
  • 클라이언트에서는 아래처럼 인스턴스를 얻는데, private 생성자는 Singleton1.INSTANCE를 초기화할 때 딱 한 번만 호출되므로 싱글턴이 보장된다.
    (private 이기 때문에 생성자를 호출할 수 없기 때문이다.)

  • 단 리플렉션을 사용해 private 생성자를 호출하면 객체를 두 개 이상 만들 수 있는데 이에 대한 예외처리를 따로 해줘야한다(flag 변수를 둔다던지)

리플렉션을 방지하는 법

public class SingletonTest {

    public static void main(String[] args) {
        Singleton1 singleton1 = Singleton1.INSTANCE;
    }
}
  • 이런 방식의 장점은 두 번째 방법인 static 팩토리 메서드를 사용하는 방법에 비해 명확하고 간결하다

static 팩토리 메서드

  • 두 번째 방법은 생성자와 인스턴스 필드는 private으로 접근을 차단하고 팩토리 메서드를 하나 두는 것이다.
public Object readResolve(){
	return INSTANCE;
    해당 인스턴스는 항상 상수값이므로 재 생성할때마다 나머지는 가비지 컬렉터로 이동한다.
}
  • 이 방식도 리플렉션을 통한 예외는 똑같이 적용된다.
  • 이러한 방식의 장점은

1. API를 바꾸지 않고도 싱글턴이 아니게 만들 수 있다는 것이다.

public class Singleton2 {

    private static final Singleton2 INSTANCE = new Singleton2();

    private Singleton2() {};

    public static Singleton2 getInstance() {
        return new Singleton2();
    }
}
  • 위처럼 바꿔도 클라이언트에서는 코드를 변경할 일이 없다는 것이다.
public class SingletonTest {

    public static void main(String[] args) {
        Singleton2 singleton2 = Singleton2.getInstance();
    }
}

2. 제네릭 싱글턴 팩토리로 만들 수도 있다.(아이템 30)

3. 정적 팩토리의 메서드 참조를 Supplier로 사용할 수 있다.

	Supplier<Singleton2> instance = Singleton2::getInstance;

직렬화(Serialization)

  • 위에서 살펴본 두 방법 모두, 직렬화에 사용한다면 역직렬화 할 때 같은 타입의 인스턴스가 여러개 생길 수 있다. 그 문제를 해결하려면 모든 인스턴스 필드에 transient를 추가 (직렬화 하지 않겠다는 뜻) 하고 readResolve 메소드를 다음과 같이 구현하면 된다.
    private static final transient Singleton2 INSTANCE = new Singleton2();

    private Object readResolve() {
        return INSTANCE;
    }

Enum

  • 이 책에서 가장 바람직한 방법으로 제시하는 세 번째 방법
  public enum Singleton3 {
      INSTANCE;
  }
  • 이 방법의 단점은 enum 말고 다른 상위 클래스를 상속할 수 없다는 것이다. 인터페이스는 구현 가능하다.

사실 그냥 스프링을 쓰면 된다. 빈으로 등록된 클래스는 해당 컨텍스트 내에서 싱글톤이 보장

profile
Hello, World!

0개의 댓글