Java

[이펙티브 자바] Item1 생성자 대신 정적 팩터리 메서드를 고려하라

nan2 2023. 2. 23. 20:35
반응형

클라이언트가 클래스의 인스턴스를 얻는 방법은 2가지다.

1. 클래스의 Public 생성자

2. 정적 팩터리 메서드 (static factory method)

 

 

정적 팩터리 메서드란 new 키워드를 직접 사용하는 것이 아니라 정적 팩터리 메서드 내부에서 new 를 사용해 객체를 생성한 다음 그 객체를 반환해주는 것을 말한다.

 

 

생성자와 비교했을 때 정적 팩터리 메서드의 장점은?

 

1. 이름을 가질 수 있다.

 

- 생성자 사용 방식

class Person {
    private String name;
    private String addr;
    
    // 생성자1
    public Person (String name, String addr) {
    	this.name = name;
        this.addr = addr;
    }	
    
    // 생성자2
    public Person (String name) {
    	this.name = name;
    }

    // 생성자3
    public Person (String addr) {
    	this.addr = addr;
    }
}

- public 생성자의 경우 반환될 객체에 대한 특성을 잘 설명하지 못한다.

생성자1 ~ 생성자3 모두 어떤 매개변수가 들어가든 객체를 생성하는 생성자이다.

 

- 하나의 시그니처는 하나의 생성자만 가질 수 있다.

여기서, 시그니처란 메서드명, 매개변수의 순서, 타입, 갯수를 의미하는데 생성자2의 매개변수 순서, 타입, 갯수가 생성자3과 동일하기 때문에 저 코드는 컴파일 오류가 발생한다.

 

애초에 생성자2와 생성자3이 함께 존재할 수 없다.

 

- 정적 팩터리 메서드 방식

class Person {
    private String name;
    private String addr;
    
    // 기본 생성자
    public Person () {
    }	
    
    // 정적 팩터리 메서드
    public static Person createByName(String name) {
    	return new Person().setName(name);
    }

    // 정적 팩터리 메서드
    public static Person createByAddr(String addr) {
    	return new Person().setAddr(addr);
    }

}

 

정적 팩터리 메서드는 반환될 객체에 대한 특성을 메서드의 이름으로 유추할 수 있게 해준다.

또한, 하나의 시그니처는 하나의 생성자만 가질수 있지만 정적 팩터리 메서드의 경우 여러개 생성이 가능하고 이름으로 인하여 헷갈리지도 않게 된다.

 

 

2. 호출할 때 마다 새로운 객체를 생성할 필요가 없다.

 

객체를 생성하는 것 자체가 많은 비용을 소모하는 것이기 때문에 정적 팩터리 메서드를 이용하여 호출될때마다 만들어져 있는 객체를 반환해주면 불필요한 객체의 생성을 막을 수 있다.

 

 

3. 하위 자료형 객체를 반환할 수 있다.

 

정적 팩터리 메서드가 객체를 반환할 때 객체의 하위 클래스 타입의 객체를 반환할 수 있다. (상속관계인 경우)

 

 

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

 

EnumSet의 noneOf() 메서드이다.

   public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        Enum<?>[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }

 

매개변수 elementType이 무엇인지에 따라서 반환할 객체가 RegularEnumSet<> 이 될 수도 있고, JumboEnumSet<> 이 될 수도 있다. 이때 주의할 점은 반환될 객체의 하위 클래스만 가능하다. 

장점 3번을 의미함 -> 위의 예제에서 EnumSet의 하위클래스인 RegularEnumSet와 JumboEnumSet 타입의 객체가 반환될 수 있다.

 

 

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

 

 

정적 팩터리 메서드의 단점은?

 

1. public이나 protected 타입의 생성자가 아닌 private 생성자만 있기 때문에 상속관계의 하위 클래스를 만들 수 없다.

 

2. 정적 팩터리 메서드는 개발자가 찾아서 사용하기 어렵다. 

반응형