객체가 인스턴스화가 필요하지 않다면 private 생성자를 사용하자

2020-11-14

클래스를 만들다보면, 단순히 정적 메서드정적 필드만을 담긴 클래스를 만들 때가 있다. 객체 지향적으로 사고하지 않는 이들이 종종 남용하는 방식이기에 그리 곱게 보이지는 않지만, 분명 나름의 쓰임새가 있다.

예를 들어 java.util.Collections 처럼 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드를 모아놓을 수 있다. 또한 final 클래스와 관련한 메서드들을 모아놓을 때도 사용한다. 또한 final 클래스 와 관련한 메서드들을 모아놓을 때도 사용한다. final 클래스를 상속해서 하위 클래스에 메서드를 넣는 건 불가능하기 때문이다.

이런 클래스들은 new 연산자를 이용해 인스턴스로 만들어 사용하려고 설계한 것이 아니다. 그치만 이런 클래스를 만들고, 생성자를 따로 명시해주지 않으면 컴파일러가 빈 생성자를 자동적으로 만들게 된다.

실제로 공개된 API들에서도 이처럼 의도치 않게 인스턴스화할 수 있게 된 클래스가 종종 발견된다.

추상클래스로 만드는 것도 인스턴스화를 막을 수 없다. 왜냐하면 하위 클래스를 만들어 인스턴스화 하면 되기 때문이다. 그리고 추상클래스로 만들면, 이를 본 개발자는 상속해서 쓰라고 오해할 수도 있기 때문에 더 큰 문제가 된다.

private 생성자 만들기

생성자를 따로 명시해주지 않았을 때, 빈 생성자가 만들어지는데, 모든 클래스를 생성자가 있어야 하기 때문이다.

생성자를 갖고있지 않는 클래스가 있으면, 컴파일러자동적으로 만들어주기 때문에 문제가 발생하게 되는 것이다.

그러면 개발자가 생성자를 만들어서 private으로 선언해주면 해결될 일이다.

public class Cons {
    private Cons() {
    }

    private static final int SOME_VALUE = 5;

    public static int getValue() {
        return SOME_VALUE;
    }
}

이렇게 private으로 만든 생성자가 있으면, 더 이상 자동적으로 생성자가 만들어지지도 않고, 접근자를 private으로 선언해줬기 때문에, 외부에서도 Cons에 대한 새로운 인스턴스를 만들어내지 못한다.

또 한가지 특징은, 상속이 불가능해진다. 왜냐하면 하위 클래스의 인스턴스를 만들 때는, 상위 클래스의 생성자를 호출하게 되는데, 상위 클래스의 생성자가 private이니 생성자에 접근할 수 있는 길이 없기 때문이다.

정리

인스턴스가 필요없는 객체는 private 생성자를 만들어주자!