Home 인스턴스 필드가 없는 클래스는 정적으로 공개해야 하는가? (유틸리티 클래스)
Post
Cancel

인스턴스 필드가 없는 클래스는 정적으로 공개해야 하는가? (유틸리티 클래스)

프리코스 1주차 숫자 야구 미션에서 나는 아래와 같이 입력 값을 받는 코드를 작성했었다.

  • InputView
1
2
3
4
5
6
7
8
9
10
11
12
public class InputView {  

	public String inputUserNumber() {  
		System.out.print(GameMessage.INPUT_NUMBER);  
		return Console.readLine();  
	}  
	  
	public Integer askRestart() {  
		System.out.println(GameMessage.ASK_RESTART);  
		return Integer.parseInt(Console.readLine());  
	}  
}

이렇게 만든 InputView 클래스를 Controller에서 아래와 같이 사용했다.

  • GameController
1
2
3
4
5
6
7
8
9
10
public class GameController {  
	private final InputView inputView;  
	/...
	  
	public GameController() {  
		this.inputView = new InputView();  
		/...
	}
	/...
}

구현 후 이렇게 필드가 없는 클래스를 static 메서드로만 구성되도록 변경하는 것을 고려해야 한다는 내용을 보게 되었다.

찾아보니 이러한 클래스를 유틸리티 클래스라고 부른다.

그럼 유틸리티 클래스로 만들면 어떠한 장점이 있을까?

유틸리티 클래스

1
2
3
4
5
6
7
8
9
10
public final class UtilityClass {

	public static void method() {
	}

	public static void method2() {
	}

	/...
}

static 메서드로만 구성된 클래스로 여러 클래스에서 공통적으로 자주 사용되는 메서드들을 모아놓은 클래스를 뜻한다.

매개 변수에 대해 작업을 수행하는 정적 메서드만 있는 클래스이며, 이 클래스는 Stateless로 사용하여 멀티스레드 환경에서 Thread-safe 하다.

  • 보통 상속을 막기위해 final로 선언한다.
  • 생성자를 private으로 선언하여 초기화 가능성을 막는다.

일반적으로 유틸리티 클래스를 고려하는 예시로는 문자열 조작, 날짜 및 시간 형식 지정, 수학적 계산, 파일 I/O 작업 등이 있다.

그렇다면 이러한 유틸리티 클래스의 장단점은 뭘까?

장점

  • 인스턴스화 해줄 필요가 없기 때문에 사용이 간편하다.
  • 재사용한 기능을 캡슐화하고 제공해준다.
  • 상태를 갖지 않고 다른 객체에 의존하지 않으므로 하나의 모듈로서 작동한다.

단점

  • 유지보수가 어렵다.
  • 잘 관리하지 않으면 무분별하게 Method들이 추가되며 단일 책임 원칙을 위반하기 쉽다.
    • 개인이 개발할 경우 이런 일이 적을 수 있으나, 다수의 개발자가 함께 개발한다면 부분별하게 메서드들이 유틸리티 클래스에 포함되며 객체 지향이 깨질 수 있다.
  • 보통 인터페이스나 추상 클래스에 의존함으로써 구현체를 갈아끼울 수 있는 유연성이 제공되지만, 유틸리티 클래스는 불가능하다.

결론

이렇게 장단점을 알고 고민해보았다.

나의 결론은 입출력이나, 문자열 조작 등의 부분에는 유틸리티 클래스를 사용하는 것이 좋다고 생각한다.

실제로 공통적으로 사용될 수 있는 부분이고 필드 값을 가질 수 없는 구조의 클래스들이며, 무분별하게 메서드를 추가할만한 클래스들이 아니라고 생각하기 때문이다.

단, 입력 값에 대한 검증 부분에 대해서는 여전히 고민된다. 미션과 같은 어떻게 보면 간단한 구조에서는 검증 부분을 모두 유틸리티 클래스로 추출하여 관리하는 것이 가독성이나 관리 측면에서 뛰어나다.

하지만 프로그램이 커진다고 생각하면?

예를 들어 PlayerNumber만 입력받았었는데 이와 비슷한 입력받는 객체가 추가된다면 PlayerNumber를 상속해서 검증부분은 재정의하여 사용할 수 있다.

이런 경우나 또 다른 검증이 필요한 객체들이 많이 생겨난다면 유틸리티 클래스로 관리했을 때 어떤 검증이 해당 객체에 필요한 검증인지 알기 힘들 수 있고 복잡성이 증가하며, 더 번거로워질 수 있다고 생각했다.

우선 나는 미션에서는 유틸리티 클래스로 입출력 및 검증 부분을 관리하는 것을 선택했다.

하지만 이렇게 간단한 미션이 아닌 어떤 프로그램을 개발한다고 가정했을 때 나는 객체 내부에 검증 로직을 둘 것 같다. 가독성 및 유지보수 관점에서 더 나은 선택이 될 것이라고 생각한다.

만약 유틸리티 클래스를 사용하고 싶다면 꼭 아래의 주의사항을 고려하도록 하자.

유틸리티 클래스를 사용할 때 주의점

  • 위에 기술한 단점을 보고 해당 단점이 문제가 없을 것 같을 때 사용하자.
  • 유틸리티 클래스는 어떠한 상태도 가져서는 안된다.
  • Input을 넣으면 Output을 반환하는 순수한 형태여야 한다.
  • 하나의 유틸리티 클래스에 무분별하게 메서드를 집어넣지 말고 메서드의 역할에 맞는 클래스에 분리하여 사용한다.
This post is licensed under CC BY 4.0 by the author.