정적 팩토리 메서드 패턴

김수혁·2024년 2월 1일

Spring

목록 보기
4/4

정적 팩토리 메서드


개발자가 구성한 Static Method를 통해 간접적으로 생성자를 호출하는 객체를 생성하는 디자인 패턴이다. 별도의 객체 생성의 역할을 하는 클래스 메서드를 통해 간접적으로 객체 생성을 유도하는 것이다.
이 정적 메서드를 통칭적으로 정적 팩토리 메서드 패턴이라고 한다.

정적 팩토리 메서드 생성 예시

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 book = Book.titleOf("윌리웡카");
}

네이밍 규칙

  1. from : 하나의 매개 변수를 받아 객체를 생성
//	from : 매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드
Date d = Date.from(instant);
  1. of : 여러개의 매개 변수를 받아 객체를 생성
//	of : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드
Set<Rank> faceCardsd = EnumSet.of(JACK, QUEEN, KING);
//	valueOf : from과 of의 더 자세한 버전
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  1. getInstance | instance : 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음
//	instance 혹은 getInstance : (매개변수를 받는다면)  매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지는 않는다.
StackWalker luke = StackWalker.getInstance(options);

Calendar instance = Calendar.getInstance();
  1. newInstance | create : 항상 새로운 인스턴스를 생성
// create 혹은 newInstance : instance 혹은 getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환함을 보장한다.
Object newArray = Array.newInstance(classObject, arrayLen);
  1. get[OrderType] : 다른 타입의 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음
//	getType : getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의하ㅏㄹ 때 쓴다. Type은 팩터리 메서드가 반환할 객체의 타입이다.
FileStore fs = Files.getFileStore(path);
  1. new[OrderType] : 항상 다른 타입의 새로운 인스턴스를 생성
//	newType : newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다. Type은 팩터리 메서드가 반환할 객체의 타입이다.
BufferedReader br = Files.newBufferedReader(path);
//	type : getType과 newType의 간결한 버전
List<Complaint> litany = Collections.list(legacyLitany);

장점

1. 생성 목적에 대한 이름 표현이 가능하다.
적절한 메서드 네이밍을 통해 반환될 객체의 특성을 한번에 유추 가능하게 해준다.

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");
}

위의 코드와 같이 정적 팩토리 메서드를 호출함으로써 생성될 객체의 특성에 대하 쉽게 묘사할 수 있어 코드의 가독성을 높여준다.

2. 인스턴스에 대해 통제 및 관리가 가능하다.
메서드를 통해 한단계 거쳐 간접적으로 객체를 생성하기 때문에, 기본적으로 전반적인 객체 생성 및 통제 관리를 할 수 있게 된다. 필요해 따라 항상 새로운 객체를 생성해서 반환할 수도 있고, 객체 하나만 만들어두고 이를 공유하여 재사용하게 하여 불필요한 객체를 생성하는 것을 방지할 수 있다.
대표적인 예로는 싱글톤 디자인 패턴이 있다.

3. 하위 자료형 객체를 반환할 수 있다.
클래스의 다형성의 특징을 응용한 정적 팩토리 메서드 특징이다.

4. 인자에 따라 다른 객체를 반환하도록 분기할 수 있다.
메서드이니 매개변수를 받을수 있을테고, 메서드 블록 내에서 분기문을 통해 여러 자식 타입의 인스턴스를 반환하도록 응용 구성이 가능하다.

5. 객체 생성을 캡슐화 할 수 있다.
구현부를 외부로부터 숨길 수 있어 캡슐화 및 정보 은닉을 할 수 있다.
이러한 점은 사용하고 있는 구현체를 숨겨 의존성을 제거해주는 장점도 지니고 있다.

단점

1. private 생성자일 경우 상속 불가능
생성자를 private 접근 제어자로 설정하게 된다. 따라서 상속을 이용한 확장이 불가능해진다.
2. API 문서에서의 불편함
생성자는 하나의 자바 프로그래밍 언어의 스펙이기 때문에 JavaDoc 같은 문서에서 상단에 정의되어 있기 때문에 빠르게 그에 대한 스펙 검색을 할 수가 있지만 정적 팩토리 메서드는 개발자가 임의로 만든 메서드이기 때문에 수많은 메서드를 뒤져서 찾아 이해해야 한다.
이러한 문제는 네이밍 컨벤션을 지켜 극복가능하다.

참고


profile
안녕안녕안녕

0개의 댓글