정적 팩토리 메소드

이수찬·2023년 4월 3일
0

[정적 팩토리 메소드란?]

정적 팩토리 메소드란 객체를 생성하는 메소드를 말한다.

그렇다면 생성자를 사용하지 않고, 정적 팩토리 메소드를 사용하는 이유는 무엇일까?
생성자의 경우 다음과 같이 오버로딩을 하면, 새로운 생성자들을 만들 수 있지만, 생성자에 어떤 매개변수가 필요한지 알 수 없다.
이와 달리 정적 팩토리 메소드는 생성자가 가지지 못한 여러 장점들을 가지는데 하나씩 알아보자.

[1. 이름을 가진 생성자]

public class Member {

    MemberType memberType;
    String name;

    public Member(MemberType memberType, String name) {
        this.memberType = memberType;
        this.name = name;
    }

    public Member(String name) {
        this.memberType = MemberType.NORMAL;
        this.name = name;
    }


}
public class main {

    public static void main(String[] args) {

        Member lisa = new Member(ADMIN, "lisa");
        // 해당 생성자로는 어떤 역할을 하는 회원을 생성하는지 알 수 없다.
        Member member = new Member("suchan");
    }

}

위와 같은 클래스에서는 new Member("suchan")가 어떤 역할을 하는 회원을 생성하였는지 알 수 없다.
정적 팩토리 메소드는 이름을 가지기에 어떤 역할을 하는 회원을 만들었는지 알 수 있다.

public class Member {

    MemberType memberType;
    String name;

    private Member(MemberType memberType, String name) {
        this.memberType = memberType;
        this.name = name;
    }

    private Member(String name) {
        this.memberType = MemberType.NORMAL;
        this.name = name;
    }

    public static Member createNormalMember(String name) {
        return new Member(name);
    }


}
public class main {

    public static void main(String[] args) {

        Member member = createNormalMember("suchan");
    }

}

정적 팩토르 메소드의 이름(createNormalMember)을 통해 memberType이 Normal인 회원을 생성한다는 것을 알 수 있다.
결국 정적 팩토르 메소드는 어떤 회원이 반환되는지를 유추할 수 있어,
코드의 가독성을 높여준다.

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

enum 타입과 같이 자주 사용하는 요소가 정해져있거나, 사용되는 값의 개수가 정해져 있으면 정적 팩토리 메소드를 통해 해당 값을 미리 생성해두고, 조회할 수 있는 구조로 만들 수 있다.
주로 같은 객체가 자주 요청되고, 객체의 생성비용이 크다면, 정적 팩토리 메소드를 활용하여 객체를 생성하자.

public final class Boolean implements java.io.Serializable, Comparable<Boolean> {
	
	public static final Boolean TRUE = new Boolean(true);
	public static final Boolean FALSE = new Boolean(false);
	...
	public static Boolean valueOf(boolean b) {
		return (b ? TRUE : FALSE);
	}
}

[3. 반환 타입의 하위 타입 객체 반환 가능]

정적 팩토리 메소드를 사용하여, 상속을 활용하면 반환 타입의 하위 타입을 반환할 수 있다.
다음과 같이 과일의 당도에 따라 과일이 지정되어있는 경우, 분기처리를 통해
하위 타입 객체를 반환할 수 있다.

public class Fruit {

    int brix; // 당도

    public static Fruit from(int brix) {

        if (brix > 12) {
            return new Banana();
        } else if (brix > 10) {
            return new Apple();
        } else {
            return new StrawBerry();
        }

    }

}

[4. 입력 변수에 따라 매번 다른 클래스 객체를 반환 가능]

EnumSet의 경우 관리하는 원소의 개수가 64개 이하인 경우 ReqularEnumSet을 반환하고, 이상인 경우 JumboEnumSet을 반환한다.
이와 같은 경우 개발자는 EnumSet를 상속받은 ReqularEnumSet과 JumboEnumSet의 존재를 모르더라도, EnumSet사용할 수 있게 해준다.

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

[5. 객체의 생성을 캡슐화]

정적 팩토리 메소드를 이용해 객체의 생성을 캡슐화할 수 있는데, 대표적인 예로는 dto를 entity로 entity를 dto로 변환할때 사용가능하다.

@Getter
public class MemberDto {

    private String name;
    private MemberType memberType;


    public static Member from(Member member) {
        return new Member(member.getName(), member.getMemberType());
    }

}

기본적으로 db에 저장하는 경우를 제외하고는 entity 대신 dto를 사용하여 entity 스팩을 노출하지 않는데, 정적 팩토리 메소드를 사용하면, 내부 구현을 외부에 보여주지 않고, 쉽게 변환할 수 있다.

물론 정적 팩토리 메소드 또한 단점이 존재한다.

[1. private 생성자의 경우 상속 불가능]

=> 부모클래스를 자식클래스에 상속하기 위해서는 생성자의 접근제어자가
public이거나 protected여야 하는데, 정적 팩토리 메소드만 제공할 경우
상속이 불가능하다.

0개의 댓글