클라이언트가 클래스의 인스턴스를 얻는 수단은 보통 public 생성자이다.
하지만 클래스는 생성자와 별도로 정적 팩토리 메서드(static factory method)를 제공할 수 있다.
아래의 valudOf 메서드는 기본 타입인 boolean 값을 받아 Boolean 객체 참조로 변환하는 정적 팩토리 메서드이다.
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
정적 팩토리를 사용하는 이유는 크게 다섯 가지로 볼 수 있다.
1. 이름을 가질 수 있다.
public 생성자를 통해 클래스의 인스턴스를 생성하면 파라미터와 생성자 자체만으로 반환될 객체의 특성을 제대로 설명하기 어렵다. 반면 정적 팩토리 메서드를 이용하면 반환될 객체의 특성이 name이라는 것을 알기 쉽다.
public class Item {
String name;
public Item(String name){
this.name = name;
}
public static Item withName(String name){
return new Item(name);
}
public static void main(String[] args) {
Item item = new Item("item1"); // 기본 생성자
Item item2 = Item.withName("item1"); // 정적 팩토리 메서드
}
}
생성자는 시그니처 제약이 존재하는데 이는 똑같은 타입을 파라미터로 받는 생성자가 존재할 수 없다는 의미이다.
아래의 경우 String 타입의 파라미터를 받는 생성자가 두 개가 존재하기 때문에 에러가 발생한다.
public class Item {
String name;
String address;
public Item(String name){
this.name = name;
}
public Item(String address){
this.address = address;
}
}
이런 경우는 정적 팩토리 메서드를 만들어 사용한다. 정잭 팩토리 메서드도 같은 타입의 파라미터를 받는데도 위의 경우와 달리 에러가 나지 않는 이유는 정적 팩토리 메서드는 이름을 가질 수 있기 때문이다.
public class Item {
String name;
String address;
public Item(String name){
this.name = name;
}
public static Item withName(String name){
return new Item(name);
}
public static Item withAddress(String address){
return new Item(address);
}
}
2. 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.
반복되는 요청에 같은 객체를 반환하는 식으로 정적 팩토리 방식의 클래스는 언제 어느 인스턴스를 살아 있게 할지를 철저히 통제할 수 있다. item("item")은 매번 호출될 때마다 새로운 인스턴스를 반환하는 반면 getItem은 HELLO라는 객체만 반환한다.
public class Item{
String name;
public Item(){}
private static final Item ITEM = new Item(); //final 객체 생성
public static Item getItem(){
return HELLO;
}
public Item(String name){
return new Item(name);
}
public static void main(String[][ args){
Item item = new Item("item1"); //매번 호출할 때마다 새로운 Item 객체 반환
Item item3 = Item.getItem();//항상 이름이 HELLO인 Item 객체 반환
}
}
대표적인 예로는 Boolean.valueOf(boolean)메서드가 있다.
3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.