(디자인 패턴) 정적 팩토리 메서드 패턴
정적 팩토리 메서드 패턴
팩토리 메서드 패턴
개념
- 객체 생성의 책임을 메서드에 위임하는 디자인 패턴
- 일반 생성자 대신 정적 메서드를 통해 객체를 생성하고, 객체 생성에 대한 더 많은 제어 및 로직과 유연성을 제공하여 다양한 형태로 객체 생성이 가능하다.
예시 코드
class Car {
private String name;
// 생성자를 private로 선언하여 외부에서 생성자 호출 불가
private Car(String name) { this.name = name; }
// 정적 팩토리 메서드
public static Car from(String title) {
return new Car(name);
}
}
- 생성자를 private으로 선언하여 외부에서 생성자를 통한 인스턴스 생성을 막는다.
- 메서드를 통해 객체를 생성하여 메서드의 생성 관련 로직을 추가하여 유연한 객체 생성을 할 수 있도록 한다.
특징
1. 메서드 명을 통해 생성 목적을 나타낼 수 있다.
생성 목적에 따라 생성자를 오버로딩하는 방식을 통해 다양한 형태로 구분할 순 있지만, 생성자의 특징을 구분할 순 없다. 그래서 개발자는 생성자를 통해 객체를 생성하려면 인자 순서 및 내부 구조를 알고 있어야 목적에 맞게 객체를 생성할 수 있다. 따라서, 매개변수만으로는 객체의 특성을 구분할 수 없다.
반면, 메서드는 이름을 가지고 있기 때문에 각 메서드에 생성된 객체의 특성에 맞는 이름을 부여해주어 코드의 가독성을 높일 수 있다.
2. 다양한 객체를 반환할 수 있다.
같은 타입의 객체를 반환하는 여러 정적 메서드를 제공할 수 있다. 메서드의 유연성을 통해 조건에 따라 반환되는 객체의 형태를 달리할 수 있다.
일반적으로 인자를 받아 인자의 따라 분기문을 통해 여러 타입의 인스턴스를 반환하도록 구성이 가능하다.
3. 미리 인스턴스를 생성하여 반환할 수 있다.
인스턴스를 미리 생성하고, 이를 공유하여 재사용하게 하여 불필요한 객체를 생성하는 것을 방지할 수 있다.
동일한 객체를 캐싱하여 반환하고, 이는 불변 객체의 경우에 특히 더 유용하다.
4. 서브타입의 객체를 반환할 수 있다.
public interface Animal {}
public class Dog implements Animal {}
public class Cat implements Animal {}
public class AnimalFactory {
public static Animal createAnimal(String type) {
if (type.equals("Dog")) {
return new Dog();
} else if (type.equals("Cat")) {
return new Cat();
} else {
throw new IllegalArgumentException("Unknown animal type");
}
}
}
매서드 호출을 통해 반환할 객체의 인스턴스가 하위타입의 인스턴스가 될 수 있어 유연성을 가진다.
5. 객체 생성을 캡슐화 할 수 있다.
생성자를 통해 객체 생성의 경우 외부에 내부 구현을 드러내야하는 것에 반해 정적 팩토리 메서드를 통한 객체 생성의 경우 구현부를 외부로부터 숨길 수 있다. 이러한 특징으로 정보 은닉성을 가진다.
네이밍 규칙
- 메서드의 역할을 이름을 통해 쉽게 구분하기 위해서 독자적인 네이밍 컨벤션 (Naming Convetion)이 존재한다. 이는 통상적으로 개발자들간의 규칙처럼 사용된다.
(1) from : 하나의 매개변수를 받아 해당 타입의 인스턴스를 반환하는 경우
public record ExampleResponse(
Long id,
String name
) {
public static ExampleResponse from (Example example) {
return new ExampleResponse(example.getId(), example.getName());
}
}
(2) of : 여러개의 매개변수 받아 적절한 타입의 인스턴스를 반환하는 경우
public record Animal(
String name
) {
public static Animal from (String name, String type) {
if (type.equals("Dog")) {
return new Dog(name);
} else if (type.equals("Cat")) {
return new Cat(name);
}
}
}
(3) valueOf : from과 of 대신 통합하여 사용
(4) instance 또는 getInstance : 인스턴스를 반환하지만, 동일한 인스턴스가 반환된다는 보장은 없음
(5) create 또는 newInstance : 매번 새로운 인스턴스를 반환하는 경우
(6) getType : 팩토리 클래스와 다른 클래스의 인스턴스를 반환하는 경우
(7) newType : 팩토리 클래스와 다른 클래스의 새로운 인스턴스를 반환하는 경우