Kernel 360에서 파이널 프로젝트를 하던 중 정적 팩토리 메서드
라는 단어가 많이 나와서 한 번 정리를 해보도록 했다.
정적 팩토리 메서드는 Static Factory Method로 개발자가 생성자를 호출해서 객체를 생성하는 것 대신에 static 을 사용해서 간접적으로 생성자를 호출해서 생성하는 디자인 패턴이라고 한다.
class Book {
private String title;
// 생성자를 private화 하여 외부에서 생성자 호출 차단
private Book(String title) { this.title = title; }
// 정적 팩토리 메서드
public static Book titleOf(String title) {
return new Book(title); // 메서드에서 생성자를 호출하고 리턴함
}
}
public static void main(String[] args) {
// 정적 메서드 호출을 통해 인스턴스화된 객체를 얻음
Book book1 = Book.titleOf("어린왕자");
}
이렇게 생성자 대신에 정적 팩토리 메서드를 통해서 객체를 생성하면 단순히 생성자의 역할을 대신 이행해주는 것 뿐만이 아니라 개발자가 좀 더 가독성 좋은 코드를 작성하고 객체 지향적으로 프로그래밍 할 수 있도록 도와준다.
클래스를 설계할 때 다양한 타입의 객체를 생성하기 위해서 생성 목적에 따라 생성자를 오버로딩하여 사용한다. 이렇게 객체를 new 키워드를 통해서 생성하려면 개발자가 해당 생성자의 인자 순서와 내부 구조를 알고 있어야 목적에 맞게 객체를 생성할 수 있다.
예를 들어 코드를 보여주겠다.
class Car {
private String brand;
private String color = "black";
public Car(String brand, String color) {
this.brand = brand;
this.color = color;
}
public Car(String brand) {
this.brand = brand;
}
}
public static void main(String[] args) {
// 검정색 테슬라 자동차
Car teslaCar = new Car("Tesla");
// 빨간색 BMW 자동차
Car bmwRedCar = new Car("BMW", "Red");
}
class Car {
private String brand;
private String color;
// private 생성자
private Car(String brand, String color) {
this.brand = brand;
this.color = color;
}
// 정적 팩토리 메서드 (매개변수 하나는 from 네이밍)
public static Car brandBlackFrom(String brand) {
return new Car(brand, "black");
}
// 정적 팩토리 메서드 (매개변수 여러개는 of 네이밍)
public static Car brandColorOf(String brand, String color) {
return new Car(brand, color);
}
}
public static void main(String[] args) {
// 검정색 테슬라 자동차
Car teslaCar = Car.brandBlackFrom("Tesla");
// 빨간색 BMW 자동차
Car bmwRedCar = Car.brandColorOf("BMW", "Red");
}
위의 예시와 같이 생성자 대신에 정적 팩토리 메서드를 호출함으로써 생성될 객체의 특성에 대해 쉽게 묘사할 수 있어 가독성을 높여준다.
이 이유가 정적 팩토리 메서드를 사용하는 가장 중요한 이유이며 이외에도 몇 가지 이유가 있다.
인스턴스에 대한 통제 및 관리가 가능하다
메서드를 통해 한단계 거쳐 간접적으로 객체를 생성하기 때문에, 기본적으로 전반적인 객체 생성 및 통제 관리를 할 수 있게 된다. 즉, 필요에 따라 항상 새로운 객체를 생성해서 반환할 수도 있고, 아니면 객체 하나만 만들어두고 이를 공유하여 재사용하게 하여 불필요한 객체를 생성하는 것을 방지 할 수 있다
하위 자료형 객체를 반환할 수 있다.
interface SmarPhone {}
class Galaxy implements SmarPhone {}
class IPhone implements SmarPhone {}
class Huawei implements SmarPhone {}
class SmartPhones {
public static SmarPhone getSamsungPhone() {
return new Galaxy();
}
public static SmarPhone getApplePhone() {
return new IPhone();
}
public static SmarPhone getChinesePhone() {
return new Huawei();
}
}
위의 코드처럼 클래스의 다형성의 특징을 응용해서 메서드 호출을 통해 얻을 객체의 인스턴스를 자유롭게 선택할 수 있는 유연성을 갖는다.