본문 바로가기

IT/이펙티브자바 3E

[Effective Java] 아이템 1. 생성자 대신 정적 팩터리 메서드를 고려하라.

안녕하세요 남갯입니다 오늘은 이펙티브 자바 3/e에 대한 내용을 공유하려고합니다.



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



클라이언트가 클래스의 인스턴스를 얻는 전통적인 방법의 수단은 public 생성자이다.


하지만 프로그래머는 클래스와는 별개로 정적 팩터리 메서드를 제공할 수 있다.

*팩토리 메소드 패턴과 다른 내용


일단 생성자 대신 정적 팩토리 메소드를 고려하는 방식은 장점과 단점이 존재한다.


5가지의 장점


1. 이름을 가질 수 있다.

생성자에 넘기는 매개변수와 생성자 자체만으로는 반환될 객체의 특성을 제대로 설명하지 못한다.

반면에 정적 팩터리는 이름만 잘 지으면 반환될 객체의 특성을 묘사가 가능하다.


예를들어 BigInteger(int, int, Random) 이라는 소스와 -  (생성자)

BingInteger.probablePrime중 어느쪽이 -  (정적팩토리메소드)


값이 소수인 BigInteger를 반환한다는 의미를 잘 설명할 것 같은지 생각해보자!

하나의 시그니처로는 생성자를 하나만 만들 수 있다.



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

인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는 식으로 불필요한 객체 생성을 피할 수 있다.

대표적인 예는 Boolean.valueOf라는것이다.


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


객체의 생성비용이 큰 같은 객체가 자주 요청되는 상황이라면 성능을 상당히 끌어올려준다.

인스턴스의 통제는 플라이웨이트패턴

* 1개에 2byte 1000개의 2kbyte일때 1000개라면 다 생성하지 않고 공유할수 있는것을 공유해서 인스턴스를 통제하는 패턴



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

이 능력은 반환할 객체의 클래스를 자유롭게 선택할 수 있는 엄청난 유연성을 선물한다.

API를 만들 때 이 유연성을 응용하면 구현 클래스를 공개하지 않고도 그 객체를 반환할 수 있어 API를 작게 유지할 수 있다.



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

반환타입의 하위타입이기만 하면 어떤 클래스의 객체를 반환하든 상관없다.



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

static 정적 팩토리 메서드를 통해 작성하므로 작성시점에는 반환할 객체 클래스가 없어도 된다.



단점


1 . 상속을 하려면 public 이나 protected 생성자가 필요하니 정적팩토리만 제공하면 상속이 불가하다.



2 . 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.

생성자처럼 api에서 명확하게 나오지 않으니 프로그래머가 일일이 인스턴스화할 방법을 찾아야한다.


다음은 정적 팩터리 메서드에서 흔히 사용하는 명명방식이다


from: 매개변수를 하나 받아서 타입의 인스턴스를 반환하는 형변환 메서드

Date d = Date.from(instance)


of : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 매서드

set<Rank> faceCards = EnumSet.of(JACK,QUEEN,KING)


valueOf : from과 of의 더 자세한버전

BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);


instance or getInstance : 매개변수로 명시한 인스턴스를 반환하지만 같은 인스턴스임을 보장하지는 않는다.

StatckWalker luke = StackWalker.getInstance(option);


create or newInstance 매번 새로운 객체를 반환한다.


getType : getInstance와 같으나 생성할 클래스가 아닌 다른 클래서의 팩터리 메서드를 정의할때 쓴다.

FileStore fs = Files.getFileStore(path)


newType : new Type과 같으나 생성할 클래스가아닌 팩터리 메서드를 정의할 때 쓴다.

BufferedReader br = Files.newBufferedReader(path);


type : getType과 newType의 간결한버전

List<Complaint> litany = Collections.List(lagacyLitany);



핵심

정적팩터미메서드와 public 생성자는 각자의 쓰임새가 있다. 상대전인 장단점을 이해하고 사용하는것이 좋다.

그렇다고 하더라도 정적 팩터리를 사용하는것이 유리한 경우가 많으므로 public 생성자의 습관을 고치자!