-
private 생성자로 noninstantiability를 강제할 것JAVA/Effective java 2020. 12. 30. 15:08
- 단순히 static 메서드와 static 필드를 모아두는 유틸리티 클래스들을 만들고 싶을 때가 있다.
- OOP적 사고와는 다소 거리가 있지만 나름의 쓰임새는 있다.
- Arrays에 배열 관련 메서드, Collections에 정적 메서드 와 팩토리 등이 그 예이다.
- 또한 final 클래스와 관련된 메서드들을 모아놓을 때도 사용하게 된다. final 클래스를 상속해서 하위 클래스에 메서드를 넣는 것은 불가능하기 때문이다.
- 따라서 이같은 유틸리티 클래스는 인스턴스를 만들어 쓰려고 설계한 게 아니다.
- 하지만 생성자를 명시하지 않으면 생성되는 기본 생성자는 public한 생성자이다.
- 클라이언트는 이 생성자가 자동 생성된 것인지 구분할 수 없다.
- 실제로 공개된 API들도 의도치 않게 인스턴스화할 수 있게 된 클래스가 있다.
상속받은 자식 클래스 - 이를 막기 위해 추상 클래스를 사용하는 경우도 있지만 인스턴스화를 막을 수는 없다.
- 상속받아서 하위 클래스를 인스턴스로 만들 수 있기 때문이다.
- 이를 본 사용자는 상속해서 쓰라는 뜻으로 오해할 수 있으니 더 큰 문제가 될 수도 있다.
- 따라서 명시적으로 private 생성자를 추가해야 한다. 그러면 클래스의 인스턴스화를 막을 수 있다.
- AssetionError는 꼭 필요하진 않지만, 그렇게 하면 의도치 않게 생성자를 호출한 경우에 에러를 발생시킬 수 있고, private 생성 자기 때문에 상속도 막을 수 있다.
- 생성자를 제공하지만 쓸 수 없기 때문에 직관에 어긋나는 점이 있는데,
- 그 때문에 위에 코드처럼 주석을 추가하는 것이 좋다.
- 부가적으로 상속도 막을 수 있다.
- 상속한 경우에 명시적이든 암묵적이든 상위 클래스의 생성자를 호출해야 하는데,
- 이 클래스의 생성자가 private이라 호출이 막혔기 떄문에 상속을 할 수 없다.
스프링의 String 관련 Util 클래스 살펴보기
- 이 클래스도 Util 클래스들 중 하나이다.
- abstract으로 만들어 놓은 것을 확인할 수 있지만 private으로 생성자를 만들지는 않고 있다.
- 왜 책에서 나온 예처럼 private 생성자를 굳이 만들지 않은 걸까??
- 앞선 예를 가지고 하위 클래스를 통해 getName에 접근해보자.
- getName()이 만들어지긴 하지만 ignored 된다고 UtilityClass.getName()으로 고쳐달라는 것을 확인할 수 있다.
- 하지만 이런 자식클래스를 만들어서 번거롭게 인스턴스를 만들 일은 없다고 생각한 게 아닐까 싶다.
참고 자료
'JAVA > Effective java' 카테고리의 다른 글
불필요한 객체를 만들지 말자 (0) 2021.01.01 리소스를 엮을 때는 의존성 주입을 선호하라 (0) 2020.12.31 private 생성자 또는 enum 타입을 사용해서 싱글톤으로 만들 것 (0) 2020.12.29 생성자 매개변수가 많다면 빌더 사용을 고려해보자 (0) 2020.12.28 생성자 대신 static 팩토리 메소드 고려해보기 (0) 2020.02.27