Effective Java TIL #1

riechu3228·2021년 1월 5일
0

생성자 대신 정적 팩터리 메서드를 고려하라.

생성자에 매개변수가 많다면 빌더를 고려하라.

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

싱글턴(singleton)이란 인스턴스(instance)를 오직 하나만 생성할 수 있는 클래스(Class)를 의미합니다.

싱글턴을 만드는 방식은 일반적으로 다음과 같은 두 가지의 방법이 있다고 한다.

1. public 필드 방식

생성자는 Private로 숨긴 후, public final static 필드로 싱글턴을 제공하는 방식입니다.

public class Elvis {
    public static final Elvis INSTANCE = new Elvis(); // (1)
    private Elvis() {}
}
  • 위에서 (1)의 코드로 인해 싱글턴임이 보장된다.

    • 단, Reflection API(AccessibleObject.setAccessible)을 사용해 Private 생성자를 호출할 경우 보장되지 않는다.
    • 이를 해결 하기 위해서는 두 번째 객체가 생성되려고 하면 예외를 던지게 하면 된다.
  • 장점

    • 해당 클래스가 싱글턴임이 API에 확연히 보인다.
    • 직관적이고 간결하다.
  • 단점

    • 직렬화(Serializable)을 구현한다고 하면, 해당 모든 인스턴스 필드를 transient로 선언하고, readResolve 메서드를 제공해주어야한다.
      • 그렇지 않으면 역직렬화 과정에서 새로운 인스턴스가 만들어지게 된다.

2. 정적 팩터리 메소드 방식

생성자는 마찬가지로 이전과 동일하게 Private로 숨긴 후, 싱글턴을 private final static 타입의 멤버에 생성하여둔 후, 정적 팩터리 메소드를 통하여 제공하는 방식입니다.

public class Elvis {
    private static final Elvis INSTANCE = new Elvis(); // (1)
    private Elvis() {}
    public static Elvis getInstance() { return INSTANCE; }
    
  • 마찬가지로 위에서 (1)의 코드로 인해 싱글턴임이 보장된다.
    • 동일하게 Reflection API에 의한 생성에는 보장되지 않을 수 있으나 동일한 방법으로 해결 가능하다.
  • 장점
    • 차후 싱글턴이 아닌 다른 형식으로 인스턴스를 제공하고 싶다고하더라도 API를 바꾸지 않아도 된다.
    • 원한다면 Generic 싱글턴 팩터리로 만들 수도 있다는 점이다.
    • 정적 팩터리의 메서드 참조를 Supplier로 사용할 수도 있다는 점이다.
  • 단점
    • public 필드의 단점과 동일합니다.
  • 위와 같은 장점이 필요하지 않다면 public 필드 방식이 좋습니다.

3. 열거 타입 방식

원소가 하나인 열거 타입을 선언하여 제공하는 방식입니다.

public enum Elvis {
   INSTANCE;
}
  • 장점
    • public 필드와 비슷하여 직관적이고 간결하다.
    • 앞선 두 방법은 직렬화, 역직렬화에서 문제가 있어 추가적인 작업을 해주어야했으나 해당 방법은 제 2의 인스턴스가 생성되는 등의 예외가 발생하지 않는다.
  • 단점
    • 만들려는 싱글턴이 열거(Enum) 외의 클래스를 상속해야 한다면 이 방법은 사용할 수 없다.
      • 열거 타입이 다른 인터페이스를 구현하도록 선언할 수는 있다.
  • 대부분의 상황에서는 원소가 하나뿐인 열거 타입 방식이 싱글턴을 만드는 가장 좋은 방법입니다.
profile
Java, Python, JavaScript Lover

0개의 댓글