본문 바로가기

자바☕/이펙티브 자바

이펙티브 자바 읽고 정리해보기 4 & 5.

728x90

아이템 4 : 인스턴스화를 막기 위해 private 생성자 활용하라

java.lang.Math 클래스나 java.util.Arrays는 기본 타입 값이나 배열 관련 메서드를 모아둔 클래스로, 실무에서 이와 같이 정적 메서드와 정적 필드만 있는 클래스를 구현할 수도 있다. 또한 java.util.Collections처럼 특정 인터페이스 구현체를 생성하는 정적 메서드(팩터리)를 모아놓을 수 있다(java 8부터는 해당 메서드를 인터페이스에 넣을 수 있다). final 클래스 관련 메서드를 모아놓을 때에도 사용할 수 있다. final 클래스를 상속한 하위클래스에 메서드를 넣을 수 없다

정적 멤버만 있는 유틸리티 클래스는 인스턴스로 사용하기 위한 목적이 아니지만, 생성자를 명시하지 않으면 컴파일러가 public 생성자를 컴파일 할 때 생성한다. 사용자는 이를 구분할 수 없다

추상 클래스로는 인스턴스화를 막을 수 없다. 하위 클래스로 인스턴스화를 할 수 있기 때문에 막을 수 없다. 이는 private 생성자를 통해 해결할 수 있다. 이는 상속을 불가능하게 하는 효과도 있다. 하위 클래스를 만들어도 private 생성자에 접근할 수가 없기 때문이다

 

아이템 5 : 자원을 직접 명시하지 말고 의존 객체 주입을 활용하라

많은 클래스가 생성 당시의 자원만을 가지고 사용하기 어렵다. 사전의 예시를 들면, 사전이 언어별로 제공될 수 있고, 테스트용 사전이 필요한 경우들이 있는데, 이런 모든 경우를 인스턴스화를 막은 정적 유틸 클래스 하나로 대응하는 것은 매우 어려운 일이다. 다양한 자원을 활용하기 위해, 한정 생성자를 제거할 수 있지만, 이는 멀티 스레드 환경에서 사용할 수 없고, 오류 발생 확률을 증가시킨다. 사용하는 자원에 따라 동작이 달라지는 클래스(사전 등)에는 정적 유틸 클래스나 싱글턴의 클래스는 적합하지 않다

이런 경우, 클래스가 다양한 인스턴스(사전이 여러 언어를)를 지원하고, 클라이언트가 선택할 수 있도록 설계한다면 대응이 가능하다. 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이다. 이는 의존 객체 주입의 한 방식으로, 맞춤법 검사기를 생성할 때 의존 객체인 사전을 주입하면 된다

public class SpellChecker {
	private final Lexicon dictionary;
    
    public SpellChecker(Lexicon dictionary) {
    	this.dictionary = Objects.requireNonNull(dictionary);
    }
    
    public boolean isVaild(String word) {}
    public List<String> suggestions(String type) {}
    
}

자원, 의존 관계의 구성에 관계없이 의존 객체 패턴은 잘 작동한다. 또한 불변을 보장해 같은 자원을 사용하려는 여러 클라이언트가 의존 객체를 안심하고 공유할 수 있다. 생성자, 정적 팩터리, 빌더 패턴 모두 사용가능하다

생성자에 자원 팩터리를 넘겨주는 방법을 응용할 수 있다. 팩터리란 호출 시마다 특정 타입 인스턴스를 반복해서 만들어주는 객체를 말한다. 즉, 팩터리 메서드 패턴을 구현한 것을 의미한다

Suplier<T> 인터페이스가 팩터리를 표현한 완벽한 예시다. 해당 인터페이스를 파라미터로 받는 메서드는 일반적으로 한정적 와일드 카드타입(아이템 31)을 사용해 팩터리의 타입 매개변수를 제한해야 한다. 이 방식을 통해 클라이언트는 자신이 명시한 타입의 하위 타입이라면 무엇이든 생성할 수 있는 팩터리를 넘길 수 있다

 

Mosaic create(Supplier<? extends Tile> tileFactory) {}

 

이 메서드는 클라이언트가 제공한 팩터리가 생성한 Tile로 구성된 Mosaic를 만드는 메서드다

의존 객체를 통해 해결이 가능하지만, 의존성이 수천 개가 되는 경우, 코드 가독성이 떨어지게 된다. 대거(Dagger), 주스(Guice), 스프링(Spring) 같은 의존 객체 주입 프레임워크를 사용하면 해소가 가능하다

728x90