본문 바로가기
Java/effective java

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

by 가영리 2022. 4. 27.
728x90

 

 

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