Effective Java - 객체 생성과 파괴(1)

SeungHyuk Shin·2021년 9월 5일
0

Effective Java

목록 보기
1/26
post-thumbnail
post-custom-banner

아이템 1. 생성자 대신 정적 팩터리 메서드를 고려하라 (p.8)


클라이언트가 클래스의 인스턴스를 얻는 전통적인 수단은 public 생성자다. 클래스는 생성자와 별도로 정적 팩터리 메서드를 제공 할 수 있다.

다음 코드는 boolean 기본 타입의 박싱 클래스인 Boolean에서 발췌한 간단한 예다

public static Boolean valueOf(boolean b){
	return b ? Boolean.TRUE : Boolean.False;
}

지금 얘기하는 정적 팩터리 메서드는 디자인패턴에서의 팩터리 메서드와 다르다.

클래스는 public 생성자 대신 정적 팩터리 메서드를 제공할 수 있다. 먼저 장점 다섯가지를 알아보자.

1. 이름을 가질 수 있다.

생성자 자체만으로는 객체의 특성을 제대로 설명하지 못한다. 반면 정적 팩터리는 객체의 특성을 쉽게 묘사 할 수 있다.

예를들어 BigInteger(int, int, Random)과 정적 팩터리 메서드인 BigInteger.probablePrime 중 어느 쪽이 '값이 소수인 BigInteger를 반환한다'는 의미를 더 잘 설명한것 같은지 생각해보라.

메소드의 시그니처인 입력 매개변수를 다르게함으로써 이 제약사항을 피해볼수도 있지만 엉뚱한것을 호출하거나 클래스 설명 문서를 읽지 않고서는 의미를 알지 못할 것이다.

2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.

대표적인 예인 Boolean.valueOf(boolean) 메서드는 객체를 아예 생성하지 않는다. 따라서 (특히 생성 비용이 큰) 같은 객체가 자주 요청되는 상황이라면 성능을 상당히 끌어올려 준다.

반복되는 요청에 같은 객체를 반환하는 식으로 정적 팩터리 방식의 클래스는 언제 어느 인스턴스를 살아 있게 할지를 철저히 통제 할 수 있다.

그렇다면 인스턴스를 통제하는 이유는 무엇일까? 인스턴스르 통제하면 클래스를 싱글턴으로 만들수도 있다. 또한 불변 값 클래스에서 동치인 인스턴스가 단 하나뿐임을 보장 할 수 있다. (a == b일때만 a.equals(b)가 성립)

3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.

이 능력은 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 '엄청난 유연성'을 선물한다. 이 유연성을 응용하면 구현 클래스를 공개하지 않고도 그 객체를 반환 할 수 있어 API를 작게 유지할 수 있다.

4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.

반환 타입의 하위 타입이기만 하면 어떤 클래스의 객체를 반환하든 상관없다. 심지어 다음 릴리스에서는 또다른 클래스의 객체를 반환해도 된다.

예를들어 EnumSet 클래스는 public 생성자 없이 오직 정적 팩터리만 제공하는데, OepnJDK에서는 원소의 수에 따라(64개 이하인지 65개 이상인지) 두가지 하위 클래스 중 하나의 인스턴스를 반환한다.

클라이언트는 두 클래스의 존재를 모른다. 클라이언트는 팩터리가 건네주는 객체가 어느 클래스의 인스턴스인지 알 수도 없고, 알 필요도 없다.

5. 정적 팩터리 메서드를 작성하는 시점에는 반환될 객체의 클래스가 존재하지 않아도 된다.

이런 유연함은 서비스 제공자 프레임워크를 만드는 근간이 된다.

서비스 제공자 프레임워크는 3개의 핵심 컴포넌트로 이뤄진다. 구현체의 동작을 정의하는 서비스 인터페이스, 제공자가 구현체를 등록할때 사용하는 제공자 등록 API, 클라이언트가 서비스의 인스턴스를 얻을때 사용하는 서비스 접근 API가 그 주인공이다.

클라이언트는 서비스 접근 API를 사용할때 원하는 구현체의 조건을 명시할 수 있다. 조건을 명시하지 않으면 기본 구현체를 반환하거나 지원하는 구현체들을 하나씩 돌아가며 반환한다.

이 서비스 접근 API가 바로 서비스 제공자 프레임워크의 근간이라고 한 '유여한 정적 팩터리'의 실체다.

이제 단점에 대해서 알아보도록 하자.

1. 정적 팩터리 메소드만 제공하면 하위 클래스를 만들 수 없다.

상속을 하려면 public인 protected 생성자가 필요하므로 상속을 이용할 수 없다.

하지만 어찌보면 이 제약은 상속보다 컴포지션을 사용하도록 유도하고 불변 타입으로 만들려면 이제 제약을 지켜야 한다는 점에서 오히려 장점으로 받아들일 수도 있다.

2.정적 팩터리 메소드는 프로그래머가 찾기 힘들다.

생성자 처럼 API 설명에 명확히 드러나지 않으니 사용자는 정적 팩터리 메서드 방식 클래스를 인스턴스화 할 방법을 알아내야 한다.

[핵심정리] 정적 팩터리 메서드와 public 생성자는 각자의 쓰임새가 있으니 상대적인 장단점을 이해하고 사용하는 것이 좋다. 그렇다고 하더라도 정적 팩터리를 사용하는게 유리한 경우가 더 많으므로 무작정 public 생성자를 제공하던 습관이 있다면 고치자.

post-custom-banner

0개의 댓글