본문 바로가기

이팩티브 자바

[Effective] 정적 팩터리 메서드

정적 팩터리 메서드는 객체 생성 역할을 하는 클래스 메서드이다.
public class Car {
    private String car;

    // 생성자
    public Car(final String car) {
        this.car = car;
    }

    // 정적 팩터리 메서드
    public static Car from(final String name) {
        return new Car(name);
    }
}

 

생성자 대신 정적 팩터리 메서드를 사용해야 하는 이유

장점 1. 이름을 가질 수 있다.

정적 팩터리 메서드를 사용하면, 메서드 이름에 객체의 생성 목적을 담아낼 수 있다.

public static Car createDefaultCar() {
    return new Car("Default");
}

위와 같은 형식으로 객체를 생성하면, 어떤 객체가 생성되는지 좀 더 구체적으로 알 수 있다.

 

‼장점 2. 같은 타입의 다른 다른 파라미터를 받아 객체를 생성할 수 있다.

public class Person {
    private String name;
    private String address;

    public Person(final String name) {
        this.name = name;
    }

    public Person(final String address) {
        this.address = address;
    }
}

 

생성자는 같은 타입의 다른 파라미터를 받을 수 없어 위의 코드는 오류가 발생한다.

 

하지만, 정적 팩터리 메서드를 사용하면, 다음과 같이 코드를 변경할 수 있다.

public class Person {
    private String name;
    private String address;

    public static Person withName(final String name) {
        Person person = new Person();
        person.name = name;
        return person;
    }

    public static Person withAddress(final String address) {
        Person person = new Person();
        person.address = address;
        return person;
    }
}

 

‼장점 3. 호출될 때마다 새로운 인스턴스를 생성할 필요가 없다.

public class Number {
    public static final int MIN_NUMBER = 1;
    public static final int MAX_NUMBER = 100;

    private static final Number[] NUMBER_CACHE = new Number[MAX_NUMBER + 1];

    private int number;

    static {
        for (int number = MIN_NUMBER; number < MAX_NUMBER; number++) {
            NUMBER_CACHE[number] = new Number(number);
        }
    }

    public Number(final int number) {
        this.number = number;
    }

    public static Number valueOf(final int number) {
        if (number < MIN_NUMBER || number > MAX_NUMBER) {
            throw new IllegalArgumentException();
        }
        return NUMBER_CACHE[number];
    }
}

Number 객체는 사용자가 값을 요청할 때마다, 새로운 객체를 생성해주는 것보다 미리 만들어 놓은 객체를 제공하는 것이 더 효율적이다. 이때, 정적 팩터리 메서드를 사용할 수 있다.

미리 만들어 놓은 Number 객체를 사용자가에 제공함으로써, 객체를 생성하는 비용을 아낄 수 있고, 싱글톤 효과 역시 얻을 수 있다.

 

‼장점 4. 변환 타입의 하위 타입 객체를 반환할 수 있다.

public interface Dog {
    public String bark();
}

public class Maltese implements Dog {
    private String name;

    @Override
    public String bark() {
        return "Wong!";
    }

    public Maltese(final String name) {
        this.name = name;
    }

    public static Dog withName(final String name) {
        return new Maltese(name);
    }
}

위와 같이 코드를 만들게 되면, Dog dog = Maltese.withName("name")으로 객체를 생성할 수 있다. 이렇게 코드를 작성하게 되면, 인터페이스만 노출이 되므로 '개념적인 무게 줄이기'가 가능하다.

 

자바 8이후 부터는 interface에서 static method를 생성할 수 있다.

public interface Dog {
    public String bark();
    
    public static Dog from(final String name) {
        return new Maltese(name);
    }
}

 

❗Convensions

from: 하나의 매개 변수를 받아서 객체 생성

of: 여러 개의 매개 변수를 받아서 객체 생성

valueOf: from과 of의 더 자세한 버전

'이팩티브 자바' 카테고리의 다른 글

[Effective] equals & hashCode  (0) 2023.03.09
[Effective] try-with-resources  (1) 2023.03.03