본문 바로가기
Java

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

by wwns 2022. 12. 6.
반응형

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

static 메서드와 static 필드만을 사용하는 것은 객체지향적으로 사고하지 않는 이들이 종종 남용하는 방식

하지만 분명 나름의 쓰임새가 있다.

-> java.lang.Math와 java.util.Arrays 처럼 기본 타입 값이나 배열 관련 메서드들을 모아놓을 수 있다.

 

정적 메서드와 정적 필드만을 담은 유틸리티 클래스

  • java.lang.Math, java.util.Arrays
  • 특히 java.util.Collections는 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드(혹은 팩터리) 모음이다
  • final 클래스와 관련한 메서들을 모음 (final 클래스를 상속해 하위 클래스에 메서드를 넣는 건 불가능하기 때문)

-> 인스턴스화 하지 않고 필요한 정적 메서드들을 이용하고 싶을 때 사용하기 때문에 함부로 상속하거나 구현하지 못하도록 해야 한다.

 

인스턴스화를 막아야 한다

  • 정적 멤버만 담은 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한 게 아니다
  • 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어주므로 private 생성자로 클래스의 인스턴스화를 막아야 한다
  • 추상 클래스로 만드는 것으로는 인스턴스화를 막을 수 없다.
    • 하위 클래스를 만들어 인스턴스화하면 그만
    • 상속해서 쓰라는 뜻으로 오해할 수 있음
public class UtilityClass {
	// 기본 생성자가 만들어지는 것을 막는다(인스턴스화 방지용)
	private UtilityClass() {
		throw new AssertionError(); // 생성자 내부 호출 시 명시적인 에러
	}
	...
}
  • 명시적 생성자가 private로 클래스 바깥에서 접근할 수 없음
  • 클래스 안에서라도 실수로 호출될 수 있으므로 AssertionError를 호출하도록 한다.
  • 생성자가 분명 존재하는데 호출할 수없다니, 그다지 직관적이지 않으므로 적절한 주석을 달아두도록 한다
  • 이 방식은 상속을 불가능하게 하는 효과도 있다
    • private으로 선언하면 하위, 상위 클래스의 생성자에 접근할 길이 막힘

util.Arrays의 예

실제 java.util.Arrays로 들어가 보면 private 생성자와 함께 주석이 달려있다.

기본 생성자를 억제하여 비인스턴스성을 보장합니다.

 

util 패키지에서 클래스의 메서드를 많이 가져다가 쓰는데 객체 생성을 하지 않았던 이유와 왜 이런 클래스를 만들어 제공했는지에 대한 이해가 생겼다. 프로젝트에서 자주 사용하는 메서드를 이런 식으로 Util 클래스를 만들어 인스턴스화 없이 사용하는 코드를 짜는 날이 왔으면 좋겠다. 잊지 말고 적용하려 노력해보자!

반응형