[JAVA] 정적 팩토리 메서드 란? (static factory method)
by mini_min
정의
객체 생성의 역할을 하는 클래스 메서드를 의미한다. 지금까지 객체를 인스턴스화할 때, 직접 생성자 (Constructor) 을 호출했는데, 객체 생성을 해주는 별도의 클래스 메서드를 만들어 간접적으로 객체 생성을 유도하는 것이다.
💡 정적 (static), 팩토리 (factory), 메서드 (method) 팩토리는 GoF 디자인 패턴 중 팩토리 패턴에서 유래한 단어로, 객체를 생성하는 역할을 분리하겠다는 취지가 있다.
예시
정적 팩토리 메서드는 다음과 같이 메서드에서 생성자를 호출하고 리턴해준다.
class Car {
private String name;
//정적 팩토리 메서드
public static Car of(String name){
return new Car(name);
}
}
public static void main(String[] args){
//정적 메소드 호출을 통해 인스턴스화된 객체를 얻음
Car mycar = Car.of("스포티지");
}
굳이 정적 팩토리 메서드를 사용하는 이유?
생성자를 두고 왜 정적 팩토리 메서드를 사용할까? 정적 팩토리 메서드 사용은 개발자가 좀 더 가독성 좋은 코드를 작성하고 객체 지향 프로그래밍을 할 수 있도록 도와준다.
😳 가령, 정적 팩토리 메서드를 사용해 이름을 부여할 수도 있고, 캡슐화도 해줄 수 있다!
생성자 대신 정적 팩토리 메서드를 고려해라.
굉장히 유명한 책 [이펙티브 자바] 의 저자인 조슈아 블로크는 “생성자 대신 정적 팩토리 메서드를 고려하라” 고 조언했다. 정적 팩토리 메서드는 어떤 특징이 있을까?
1. 이름을 부여할 수 있다.
객체의 목적에 따라 생성자를 구별해서 사용해야할 때, 정적 팩토리 메서드는 탁월한 이점이 있다. 정적 팩토리 메서드를 이용하면 메서드 이름에 객체의 생성 목적을 담아낼 수 있다.
public class staticFactoryMethod {
public static void main(String[] args) {
Cafe saleMenu = Cafe.createSaleMenu("아이스 아메리카노");
Cafe nonSaleMenu = Cafe.createNonSaleMenu("바닐라 크림 콜드부르 라떼", 6500);
}
}
class Cafe{
private String menu;
private int price;
private Cafe(String menu, int price){
this.menu = menu;
this.price = price;
}
//정적 팩토리 메서드(매개 변수 1개)
public static Cafe createSaleMenu(String menu){
return new Cafe(menu, 1000);
}
//정적 팩토리 메서드(매개 변수 2개)
public static Cafe createNonSaleMenu(String menu, int price){
return new Cafe(menu, price);
}
}
- createSaleMenu 와 createNonSaleMenu는 모두 카페 메뉴 객체를 만들어 반환하는 정적 팩토리 메서드이다. 메서드 이름만 봐도 세일 메뉴 객체를 만들어주는지, 일반 메뉴 객체를 만들어주는지 알 수 있다.
- new 를 이용해 생성자를 직접 만드는 것보다 이렇게 정적 팩토리 메서드를 가지고 객체를 생성하는 것이 훨씬 의미 파악하기 쉽다.
2. 호출할 때 마다 새로운 객체를 만들 필요가 없다.
자주 사용하는 객체를 미리 생성해놓고 조회(캐싱)할 수 있는 구조를 만들 수 있다! 정적 팩토리 메서드와 캐싱 구조를 함께 사용하면, 매번 새로운 객체를 생성할 필요가 없어진다.
class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class classRoom {
// 반에 있는 학생 객체를 저장하는 캐싱 저장소 역할
private static final Map<String, Student> cache = new HashMap<>();
//이미 저장된 학생 정보.
static {
cache.put("김민지", new Student("김민지"));
cache.put("홍길동", new Student("홍길동"));
cache.put("뉴진스", new Student("뉴진스"));
}
//정적 팩토리 메서드
public static Student from(String name){
if ( cache.containsKey(name) ){
System.out.println("이미 존재하는 학생입니다.");
return cache.get(name);
}
else {
System.out.println("새로운 학생으로, 학생 정보를 등록합니다.");
cache.put(name, new Student(name));
return cache.get(name);
}
}
}
public static void main(String[] args) {
//이미 등록된 학생 정보 가져오기
Student select1 = classRoom.from("뉴진스");
System.out.println(select1.getName());
Student select2 = classRoom.from("아이브");
System.out.println(select2.getName());
}
- 위에 처럼, classRoom 이라는 클래스에서 객체를 저장하고 관리하는 캐싱 저장소를 만들고, 정적 팩토리 메서드로 캐싱 저장소를 조회하면, 새로운 객체를 매번 만들 필요 없이 기존 객체를 사용하며 관리할 수 있다.
- 이렇게 새로운 객체 생성의 부담을 덜 수 있다는 장점이 있다.
3. 캡슐화가 가능하다.
정적 팩토리 메서드를 사용하면 외부에 내부 구현을 드러내지 않아서 캡슐화, 정보 은닉을 할 수 있다. 또한, 구현체를 숨겨 의존성을 제거해준다는 장점도 가지고 있다.
public class CafeDTO {
private Stirng name;
private int price;
public static CafeDTO of(Cafe cafe) {
return new CafeDTO(cafe.getName(), cafe.getPrice());
}
}
//Cafe -> CafeDTO
CafeDTO cafeDTO = CafeDTO.of(Cafe);
- 위에 코드를 보면 메인 메서드는 정적 팩토리 메서드 of 만 호출해서 내부 구현 내용은 모른채 객체를 반환받을 수 있다.
정적 팩토리 메서드 네이밍
- from : 하나의 매개 변수로 객체 생성
- of : 여러개의 매개 변수로 객체 생성
- getInstance / instance : 인스턴스를 생성
- newInstance / create : 새로운 인스턴스 생성
- get[OtherType] : 다른 타입의 인스턴스를 생성
- new[OtherType] : 다른 타입의 새로운 인스턴스를 생성
'Java' 카테고리의 다른 글
[JAVA] Fork join Pool (java Concurrency 툴) (0) | 2023.07.17 |
---|---|
[JSP] 천원 단위 표시 콤마 DecimalFormat (0) | 2022.09.28 |
[JAVA] 자바 - 람다식 (Lambda) / Consumer<T>, Supplier<T> (0) | 2022.09.05 |
[JAVA] 자바 - InetAddress 클래스 / URL 클래스 (0) | 2022.09.05 |
[JAVA] 자바 - 컴퓨터 네트워크 (프로토콜, 포트, IP) (0) | 2022.09.05 |
블로그의 정보
개발자 미니민의 개발로그
mini_min