클래스의 인스턴스를 얻는 전통적 수단은 public 생성자이다.
클래스는 생성자와 별도로 정적 팩터리 메서드를 제공할 수 있다.
public 생성자 대신 정적 팩터리 메서드가 좋은 이유 5가지
첫 번째. 이름을 가질 수 있다.
public class Dante {
public Dante(){ //생성자
System.out.println("HI");
}
public static void DanteWithMoney(){ // 정적 팩토리 메서드
System.out.println("I have money");
}
public static void main(String[] args) {
DanteWithMoney();
}
}
-> 생성자
- 이름이 없음
- 반환될 객체의 특성을 알기 힘듦
-> 정적 팩토리 메서드
- 이름을 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있음
매개변수와 생성자 자체만으로는 객체의 특성을 알기 힘들다. 하지만 정적 팩터리는 이름을 잘 짓는다면 객체의 특성을 쉽게 묘사할 수 있다.
두 번째. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
이 덕분에 불변 클래스는 인스턴스를 미리 만들어놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는 식으로 불필요한 객체 생성을 피할 수 있다.
대표적 예인 Boolean.valueOf() 메서드는 객체를 생성하지 않는다.
public static void main(String[] args) {
Boolean test = true;
Boolean.valueOf(test);
}
반복되는 요청에 같은 객체를 반환하는 식으로 인스턴스의 생성,파괴를 통제할 수 있다.
-> 인스턴스 클래스를 통제하는 이유?
- 클래스를 싱글턴으로 만들기
- 인스턴스화 불가능으로 만들기
- 불변 값 클래스에서 동치인 인스턴스가 단 하나뿐 임을 보장함
세 번째. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
이 능력은 반환할 객체의 클래스를 자유롭게 선택할 수 있는 유연성을 준다.
public class Dante {
public Dante(){
System.out.println("HI");
}
public static AnotherDante DanteWithMoney(){
return new AnotherDante();
}
public static void main(String[] args) {
DanteWithMoney();
}
}
class AnotherDante {
public AnotherDante(){
System.out.println("ADante");
}
}
실행결과
네 번째. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
반환 타입의 하위 타입이기만 하면 어떤 클래스의 객체를 반환하든 상관 없다.
EX)
EnumSet 클래스는 public 생성자 없이 정적 팩터리만 제공함. 원소의 수에 따라 두 가지 하위 클래스 중 하나의 인스턴스를 반환함
- 원소가 64개 이하일 때, long 변수 하나로 관리하는 RegularEnumSet 인스턴스 반환
- 원소가 65개 이상일 때, long 배열로 관리하는 JumboEnumSet 인스턴스 반환
사용자는 이 두 클래스의 존재를 모르며 알 필요도 없다.
다섯 번째. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
이런 유연함은 서비스 제공자 프레임워크(service provider framework)를 만드는 근간이 된다.
서비스 제공자 프레임 워크는 3개의 핵심 컴포넌트로 이루어져 있다.
- 서비스 인터페이스 : 구현체의 동작 정의
- 제공자 등록 API : 제공자가 구현체를 등록할 때 사용
- 서비스 접근 API : 클라이언트가 서비스의 인스턴스를 얻을 때 사용
대표적으로 JDBC가 있다.
- 서비스 인터페이스 : Connection
- 제공자 등록 API : DriverManager.registerDriver
- 서비스 접근 API : DriverManager.getConnection
정적 팩터리 메서드의 단점 2가지
첫 번째. 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.
상속을 위해서는 public이나 protected 생성자를 구현해야한다.
두 번째. 정적 팰터리 메서드는 프로그래머가 찾기 어렵다.
생성자 API처럼 명확히 드러나지 않아, 사용자는 정적 팩터리 메서드 방식 클래스를 인스턴스화 할 방법을 알아내야만 한다. 이를 방지하기 위해서 API 문서를 잘 써놓고 메서드 이름도 정해진 규약에 따라지어야 한다.
정적 팩터리 메서드와 public 생성자를 사용하기 위해 각각의 장단점을 이해하고 사용해야 한다. 그렇더라도 정적 팩터리를 사용하는 게 유리한 경우가 더 많으므로 설계를 잘해야 한다.
'Study > Effective Java' 카테고리의 다른 글
[아이템07] 다 쓴 객체 참조를 해제하라 (0) | 2022.09.30 |
---|---|
[아이템05] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.09.22 |
[아이템04] 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2022.09.13 |
[아이템03] private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2022.09.08 |
[아이템02] 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2022.08.22 |