item 04 : 인스턴스화를 막으려거든 private 생성자를 사용하라

정적 메서드와 정적 필드만 담은 클래스 만들기

이따금 단순히 정적 메서드와 정적 필드만을 담은 클래스를 만들고 싶을 때가 있을 것이다.

사용처

1. java.lang.Math, java.util.Arrays

  • 기본 타입 값이나 배열 관련 메서드들을 모아놓을 수 있음

2. java.util.Collections

  • 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드(혹은 팩터리)를 모아 놓을 수 있다.

  • 자바 8부터 이러한 메서드를 인터페이스를 넣을 수 도 있다.

3. final 클래스와 관련한 메서드들 모아놓을 때 사용

  • final 클래스를 상속해서 하위 클래스에 메서드를 넣는 건 불가능 하기 때문이다. 불변성을 위해 아예 상속 못하게 막아져 있음

정적 멤버만 담은 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한 게 아니다. 하지만 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어준다. 즉, 매개변수를 받지 않는 public 생성자가 만들어지며, 사용자는 이 생성자가 자동 생성된 것인지 구분할 수 없다.

추상 클래스로 만드는 것으로는 인스턴스화를 막을 수 없다. 하위 클래스를 만들어 인스턴스화하면 그만이다.

컴파일러가 기본 생성자를 만드는 경우는 오직 명시된 생성자가 없을 때뿐이니 private 생성자추가하면 클래스의 인스턴스화를 막을 수 있다.

유틸리티 클래스 설계

읽어보면 좋은 블로그 글 : utillity class는 무엇으로 구현하는 것이 좋을까?

public class UtilityClass {
    // 기본 생성자가 만들어지는 것을 막는다 (인스턴스화 방지용)
    private UtilityClass() {
        throw new AssertionError("이 클래스는 인스턴스화할 수 없습니다.");
    }

    // 유틸리티 메서드
    public static void utilityMethod() {
        // 유틸리티 메서드의 구현
        System.out.println("유틸리티 메서드 호출!");
    }
}

유틸리티 클래스를 설계할 때, private 생성자를 사용하여 인스턴스화를 방지하는 방법

  1. private 생성자:

    • private로 선언된 생성자는 클래스 외부에서 접근할 수 없어 인스턴스를 생성할 수 없다.

    • 생성자 안에서 AssertionError를 던짐으로써, 실수로라도 생성자가 호출되는 것을 방지할 수 있다. 이는 코드의 안전성을 높이는 데 기여

  2. 직관성:

    • 생성자가 존재하지만 호출할 수 없는 상황이 직관적이지 않을 수 있다. 따라서 적절한 주석을 추가하여 코드의 의도를 명확히 하는 것이 중요

  3. 상속 방지:

    • 모든 생성자는 상위 클래스의 생성자를 호출해야 하는데, private 생성자를 사용하면 하위 클래스가 상위 클래스의 생성자에 접근할 수 없게 된다. 이로 인해 상속을 통한 인스턴스화도 막힘

  4. 빌더를 사용하게 하려고 결국 private로 생성자를 막은 적이 있음 강제하기 위해

Last updated