Ga0Lee

[이펙티브 자바] 아이템 1. 생성자 대신 정적 메서드를 고려하라 본문

Java/effective java

[이펙티브 자바] 아이템 1. 생성자 대신 정적 메서드를 고려하라

가영리 2022. 4. 27. 17:55

 

 

클라이언트가 클래스의 인스턴스를 얻는 수단은 보통 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. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.