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 생략
}
객체 사이의 형변환이 필요하거나, 객체 생성이 반복되는 경우에는 생성자보다는 정적 팩토리 메소드를 활용해 보는 것이 좋을 것으로 보입니다.
🔗 참고자료
'🧑🏻💻 Dev > Java' 카테고리의 다른 글
[Java] 불변 객체(Immutable Object)와 Record (0) | 2023.04.25 |
---|---|
[Java] TreeSet에서 커스텀 객체 정렬 (0) | 2023.03.24 |
[Java] Java의 문자열 String과 친해져보자 (0) | 2023.03.09 |
[Java] 자바 정수형 배열을 리스트로 변환하기 (0) | 2023.03.04 |
[Java] 열거형 (enum) (0) | 2023.02.08 |