티스토리 뷰

static 메서드와 필드로만 구성된 클래스

 개발을 하다보면 static 메서드와 필드로만 구성된 클래스가 필요한 경우가 있다. 객체지향적인 설계는 아니지만, 다음과 같은 상황이 필요한 경우에는 유용하게 사용할 수 있다.

  • 기본 타입 값이나 처리대상 클래스와 관련된 메서드들을 모아놓은 유틸리티성 클래스의 설계
    ex) java.util.Arrays
  • 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드 또는 팩토리
    ex) java.util.Collections
  • 추가 상속을 방지하기 위한 final 클래스와 관련한 메서드들의 집합

정적 유틸리티 클래스의 설계의도

 정적 유틸리티 클래스는 인스턴스로 만들어 쓰기 위해 설계한 것이 아니다. 그런데 자바 언어에서 클래스의 생성자를 명시하지 않는 경우, 매개변수가 없는 public 생성자를 기본 생성자로 만들어준다. 클래스의 사용자는 이러한 생성자가 자동으로 생성된 것인지, 어떤 의도를 가지고 생성된 것인지 알 수가 없다.

 

 객체의 인스턴스화를 막을 수 있는 한 가지 방법은, 클래스를 추상클래스로 설계하는 것이다. 그러나 이 방법으로는 인스턴스화를 막을 수가 없다. 클래스를 상속해서 일반 클래스로 정의하면 얼마든지 인스턴스를 생성할 수 있다. 또한 추상클래스의 선언은, 사용자가 이 클래스를 상속해서 구체화해 사용하라는 의도를 표현하기도 하기 때문에 인스턴스화를 막으려는 의도랑은 상충된다.


private 생성자를 정의하면 클래스의 인스턴스화를 막을 수 있다.

public class CollectionUtils {

    private CollectionUtils() {
        throw new AssertionError();
    }

    public static boolean isEmpty(Collection<?> collection) {
        return collection==null || collection.isEmpty();
    }
    // ... 추가 기능
}

 위와 같이 기본 생성자를 명시적으로 private 선언을 해주면 클래스 바깥에서는 접근할 수가 없다. 예시 코드에서는 AssertionError 를 던지도록 해 주었는데, 이는 클래스 내부에서 실수로라도 생성자를 호출해 인스턴스화가 일어날 수 있는 가능성을 원천 차단해준다.

 

 이와 같은 방법은 클래스의 상속을 통한 인스턴스화를 막아주는 효과도 있다. 하위 클래스는 인스턴스화 시점에 상위 클래스의 생성자를 호출하게 되어있는데, private 접근 지정자는 자기 자신 클래스 외에는 다른 클래스에서는 접근이 불가능하기 때문이다.


마치며

 static 유틸 클래스는 실무에서 자주 사용하고 있던 설계이다. 지금까지 private 생성자를 통해 인스턴스화를 방지할 생각은 따로 하지 않았는데, 당연히 이 클래스는 정적유틸이다 라고 생각하는 가정을 스스로 만들었던 것 같다. 최근에 강의에서 좋은 프로그램은 제약이 많아 사용자가 설계자의 설계의도대로 사용할 수 밖에 없도록 구현되어 있다는 말을 들었다. 이번 주제도 간단하지만 이러한 맥락에서 좋은 인사이트를 준 것 같다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday