정적 팩토리 메소드

JaeYeop·2022년 1월 6일
0

정적 팩토리 메소드란?

코드 예시를 먼저 보자

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

    public static Test withName(String name) {
        Test test = new Test();
        test.name = name;
        return test;
    }

    public static Test withAddress(String address) {
        Test test = new Test();
        test.address = address;
        return test;
    }

    public static void main(String[] args) {
        Test testName = withName("Gyunny");
        Test testAddress = withAddress("Address");
    }
}

정적 팩토리 메소드는 얼핏보면 생성자와 매우 유사하다. (처음 봤을 때 왜 이렇게 하는지 이해가 안 되기도 했다..)

정적 팩토리 메소드는 생성자와 유사하지만 몇 가지 장점이 있는 객체 생성의 역할을 하는 메소드로 말할 수 있다.

비슷한거 같은데 왜 써?

몇가지 이유를 나열해보자

1. 이름 설정이 가능, 필드의 수에 제한이 없다

예시 코드를 보면 객체를 생성 할 때 어떤 변수의 초기값을 줄지 지정하고 생성 할 수 있다. (만약 이게 생성자였으면 직접 코드를 까봐야겠지)

그리고 중요한 건 만약 위 예시 코드에서 name만 초기화하는 생성자를 만들었다고 치자. 그렇다면 address를 초기화해서 생성하는 생성자는 만들 수 없다(이미 필드의 갯수가 1개인 생성자를 만들어서). 이럴 경우에도 정적 팩토리 메소드로 해결이 가능하다!

2. 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다

public class Test {
    private String name;

    private static final Test GOOD_STUDY = new Test();

    public static Test Test_goodStudy() {
        return GOOD_STUDY;
    }

    public static void main(String[] args) {
        Test test = Test_goodStudy();
    }
}

이 코드를 보면 하나의 final 객체를 계속 리턴하는 방식이다. 이와같이 중복된 값이 계속 인스턴스화되지 않게 할 수 있고, 이 방법으로 메모리를 절약할 수 있다.

3. 반환 타입을 하위 타입 개체로 할 수 있다

public interface Type {
    static Type getAType() {
        return new AType();
    }

    static Type getBType() {
        return new BType();
    }
}

class AType implements Type {
}

class BType implements Type {
}
  • interface에서 메소드에 static을 붙이면 interface에서 정의한 방법대로만 해당 메소드를 사용해야한다.

구현하고 있는 클래스를 노출시키지 않을 수 있고, 사용자 입장에서도 반환 된 클래스가 어떤 클래스인지 굳이 찾아보지 않아도 되는 장점도 있습니다.

4. 클래스 객체 반환을 개발자가 구성할 수 있다

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable
{
    public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
        EnumSet<E> result = noneOf(elementType);
        result.addAll();
        return result;
    }

    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);
    }

    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
        EnumSet<E> result = noneOf(e1.getDeclaringClass());
        result.add(e1);
        result.add(e2);
        return result;
    }
}

해당 코드를 보면 noneOf 메소드를 보면 universe의 길이에 따라 다른 반환 형태를 볼 수 있다. 이와 같이 하위 클래스의 반환 구조를 지정할 수 있다.

네이밍 컨벤션

from : 하나의 매개 변수를 받아서 객체를 생성
of : 여러개의 매개 변수를 받아서 객체를 생성
getInstance | instance : 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음.
newInstance | create : 새로운 인스턴스를 생성
get[OtherType] : 다른 타입의 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음.
new[OtherType] : 다른 타입의 새로운 인스턴스를 생성.

profile
이게 왜 틀리지... (나의 메모용 블로그)

0개의 댓글