[Java] 정적 팩토리 메서드 패턴 (Static Factory Method)

해니·2024년 12월 29일
0

Java

목록 보기
26/34
post-thumbnail

정적 팩토리 메서드 (Static factory method)란?

  • 객체의 생성을 담당하는 클래스 메서드
  • 객체를 생성할 때, 생성자를 사용하지 않고 정적 메서드(static method)를 사용한다.

📢디자인 패턴의 팩토리 메서드와는 다른 것이며, 디자인 패턴 중에는 정적 팩토리 메서드와 일치하는 것은 존재하지 않는다.



정적 팩토리 메서드의 장점



1. 이름을 가질 수 있다.


// 생성자 방식 

public class Flower {
    String name;
    String floriography;
    int price;

	// 'Flower(String, int)' is already defined 
    public Flower(String floriography, int price) {
        this.floriography = floriography;
        this.price = price;
    }

	// 'Flower(String, int)' is already defined
    public Flower(String name, int price) {
        this.name = name;
        this.price = price;
    }
    
}
  • Flower 클래스에서 첫 번째 생성자와 두 번째 생성자는 반환 타입, 매개 변수의 개수와 타입이 모두 같으므로 동일한 시그니처의 생성자이다.
    • 이미 정의된 생성자라고 컴파일 오류가 발생하는데, 각 정적 팩토리 메서드는 이름을 다르게 가질 수 있기 때문에 이를 이용하여 문제를 해결할 수 있다.
  • 정적 팩토리 메서드를 사용하면 클래스내에 여러 생성자가 있는 경우 각 생성자를 사용 할 때 보다, 어떤 객체가 반환되는지 쉽게 유추할 수 있다.

// 정적 팩토리 메서드 

public class Flower {
   String name;
   String floriography;
   int price;

   public static Flower CreateFromFloriography(String floriography, int price) {
       Flower flower = new Flower();
       flower.floriography = floriography;
       flower.price = price;
       return flower;
   }

   public static Flower CreateFromName(String name, int price) {
       Flower flower = new Flower();
       flower.name = name;
       flower.price = price;
       return flower;
   }

}



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

  • 생성자를 사용해 객체를 생성하기 위해서는 new 생성자()를 사용해야 하는데, 이때마다 인스턴스를 새로 생성한다.
  • 정적 팩토리 메서드를 사용하면 기존 인스턴스를 반환하는 방식으로 객체를 생성할 수 있다.
    • 같은 객체를 자주 요청할 때 유용하다.
    • 같은 객체를 여러 번 생성하지 않아도 되니 메모리 효율 측면에서 좋다.

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);
    }
    
    // 생략
}
  • Boolean 클래스에서 truefalse 값은 자주 사용되므로 TRUE, FALSE 인스턴스를 먼저 생성해 놓는다.
  • valueOf() 메서드를 사용할 때마다 기존에 생성해 두었던 인스턴스인 TRUE 또는 FALSE를 반환해 준다.



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


public class Grade {
...
    private static Grade of(int takenSemester) {
        if (0 < takenSemester && takenSemester <= 2) {
            return new Freshman();
        }
        if (2 < takenSemester && takenSemester <= 4) {
            return new Sophomore();
        }
        if (4 < takenSemester && takenSemester <= 6) {
            return new Junior();
        }
        if (6 < takenSemester &&<takenSemester <= 8){
            return new Senior();
        }
        ...
    }
...
}
  • 정적 팩터리 메서드를 이용하면 객체 생성시, 분기처리를 통해 하위 타입의 객체를 반환할 수 있다



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);
}
  • 입력 파라미터에 따라 다른 클래스의 객체를 반환 할 수 있다.
    • EnumSet.noneOf() 메서드는 파라미터로 부터 받은 값의 길이에 따라 RegularEnumSet<>이나 JumboEnumSet<>을 반환 한다.
  • 직접적으로 클래스 이름을 가져오지 않는 이상, 클라이언트는 정적 팩토리 메서드가 건네주는 객체가 어느 클래스의 인스턴스인지 알 수 없으며 알 필요도 없다.




정적 팩토리 메서드의 단점


1. 정적 팩토리 메서드만 제공할 경우, 상속이 불가능하다.

  • 생성자를 제공하지 않고, 오로지 정적 팩토리 메서드만을 사용해 인스턴스를 반환하는 클래스를 만들고 싶은 경우, 해당 클래스의 생성자의 접근 제어자는 private으로 해야 한다.
  • 상속을 하기 위해서는 public이나 protected가 붙은 생성자가 있어야 하는데, 그러한 생성자가 없으므로 정적 팩토리 메서드만을 제공하는 클래스는 상속을 하지 못한다.



2. 정적 팩토리 메서드를 다른 개발자들이 찾기 어렵다.

  • 개발자가 임의로 만든 정적 팩토리 메서드 특성 상, 다른 개발자들이 사용시에 정퍽 팩토리 메서드를 찾기가 어렵다고 생각 할 수 있다.
  • 정적 팩토리 메서드 같은 것은 주석-JavaDoc에선 @See-를 사용하여 나타낼 수 있다- 또는 문서화를 통해 설명을 달아놓는 게 좋다.
  • 정적 팩토리 메서드 네이밍 패턴을 사용하여 정적 팩토리 메서드임을 알아보는 데에 도움을 줄 수 있다.



정적 팩토리 메서드 네이밍 규칙


  • from : 매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드

    	Date d = Date.from(instant);

  • of : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드

    	set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);

  • valueOf : fromof의 더 자세한 버전

    	BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);

  • instance 혹은 getInstance : (매개변수를 받는다면) 매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지 않는다.

    	StackWalker luke = StackWalker.getInstance(options);

  • create 혹은 newInstance : instance 혹은 getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환함을 보장한다.

    	Object newArray = Array.newInstance(classObject, arrayLen);

  • getType : getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩토리 메서드를 정의할 때 쓴다. Type은 팩토리 메서드가 반환할 객체의 타입이다.

    	FileStore fs = Files.getFileStore(path);

  • newType : newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩토리 메서드를 정의할 때 쓴다. Type은 팩토리 메서드가 반환할 객체의 타입이다.

    	BufferedReader br = Files.newBufferedReader(path);

  • type : getTypenewType의 간결한 버전

    	List<Complaint> litany = Collections.list(legacyLitany);






출처

정적 팩토리 메서드 (Static factory method) [Effective Java]
정적 팩토리 메서드(Static Factory Method)

profile
💻 ⚾️ 🐻

0개의 댓글