Java 클래스에서 of(), from(), getInstance()와 같은 정적 팩토리 메소드를 많이 사용하는 것을 보고, 정적 팩토리 메소드를 사용하는 이유에 대해서 궁금하여 글을 정리하게 되었습니다.

 

 

1. 정적 팩토리 메소드(static factory method)는 무엇인가?

  • 정적 팩토리 메소드는 객체 생성의 역할을 하는 클래스 메소드이다.
  • 자바 코드를 짜봤다면 정적 팩토리 메소드를 써본 적이 있을 것입니다.
public class Example {
    public static void main(String[] args) {
        // 직접 생성자를 통해서 객체를 생성
        List<String> list1 = new ArrayList<>();
        list1.add("김씨");
        list1.add("박씨");
        list1.add("정씨");
        list1.add("이씨");
        list1.add("윤씨");
        
        // 정적 팩토리 메소드를 통해서 객체를 생성
        List<String> list2 = List.of("김씨", "박씨", "정씨", "이씨", "윤씨");
    }
}

위 코드는 List.of()를 사용하여 직접 생성자를 사용하지 않고, 리스트를 만드는 방법에 대한 코드입니다.

 

 

 

2. 정적 팩토리 메소드는 왜 사용하는가?

  • 사실 저도 코드를 짜면서 이 부분이 가장 의문이었습니다. 객체 생성은 생성자라는 것을 통해서 할 수 있는데, 굳이 왜 정적 팩토리 메소드를 사용해서 객체를 생성하는 것일까에 대한 의문입니다.
  • 정적 팩토리 메소드를 사용하는 이유를 알아보기 위해서는 생성자와 어떤 점이 다르고, 어떤 점에서 더 좋은 점이 있는지 먼저 알아야 합니다.

 

 

 

3. 정적 팩토리 메소드와 생성자의 차이

(1) 이름을 가질 수 있습니다.

  • 객체의 생성은 목적에 따라서 생성자를 구별해서 사용해야 합니다. 생성자는 이름을 가지고 있지 않기 때문에 목적에 맞게 객체를 생성하려면 해당 클래스의 내부 구조를 잘 알고 있어야 합니다
  • 정적 팩토리 메소드를 사용하면 객체 생성 목적에 맞게 이름을 지정할 수 있습니다. 이를 통해 얻을 수 있는 효과는 코드의 가독성을 더욱 높일 수 있습니다.

 

 

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

  • 생성자를 호출하여 객체를 가져올 때는 새로운 객체를 생성해야 합니다.
  • 하지만 만약 싱글톤처럼 미리 만들어져 있는 객체를 가져와서 사용해도 되는 상황이라면 굳이 생성자를 직접 호출해서 사용할 필요가 없습니다.
  • 이때 정적 팩토리 메소드를 이용하면 호출할 때마다 새로운 객체를 생성하지 않아도 됩니다. 정적 팩토리 메소드를 사용해서 객체의 생성을 제한하고 싶다면 객체의 생성자를 private로 설정하는 것이 좋습니다.

 

 

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

  • 생성자 역할을 하는 정적 팩토리 메소드는 반환값을 가지고 있기 때문에 하위 타입의 객체를 반환할 수 있습니다.
  • 아래는 점수만 입력하면 해당 점수에 맞는 티어의 타입을 반환해 주는 분기분을 팩토리 메소드에서 구현할 수 있습니다.
public class Level {
    public static Level of(int score) {
        if (score < 1000) {
            return new Bronze();
        } else if (score < 10000) {
            return new Silver();
        } else if (score < 100000) {
            return new Gold();
        } else {
            return new Platinum();
        }
    }
}

class Bronze extends Level {
    public Bronze() {
        System.out.println("브론즈 티어");
    }
}

class Silver extends Level {
    public Silver() {
        System.out.println("실버 티어");
    }
}

class Gold extends Level {
    public Gold() {
        System.out.println("골드 티어");
    }
}

class Platinum extends Level {
    public Platinum() {
        System.out.println("플래티넘 티어");
    }
}

 

 

(4) 객체 생성을 캡슐화할 수 있습니다.

  • 생성자에 private를 붙이고, 정적 팩토리 메소드 안에서 생성자를 호출함으로써 내부 상태를 외부에 드러낼 필요 없이 객체 생성 인터페이스를 단순화할 수 있습니다.
  • DTO에서 사용하는 from()을 한 가지 예시로 볼 수 있습니다.
  • StudentDto의 내부 구현을 모르고 있더라도 Student 객체를 정적 팩토리 메소드 from()의 파라미터로 넣어주면 해당 Student에 대한 Dto 객체를 얻을 수 있습니다.
public class StudentDto {
    private String name;
    private Integer age;
    
    private StudentDto(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    
    public static StudentDto from(Student student) {
        return new StudentDto(student.getName(), student.getAge());
    }
    
    // Getter, Setter 생략
}

 

 

 

객체 사이의 형변환이 필요하거나, 객체 생성이 반복되는 경우에는 생성자보다는 정적 팩토리 메소드를 활용해 보는 것이 좋을 것으로 보입니다. 

 

 

🔗 참고자료

정적 팩토리 메서드(Static Factory Method)는 왜 사용할까?

+ Recent posts