도서 요약 / / 2023. 2. 10. 06:51

디자인 패턴 - 팩토리 메소드(factory method) 패턴

udemy 강좌(Java Design Patterns & SOLID Design Principles)를 정리한 내용이다.

https://www.udemy.com/course/design-patterns-in-java-concepts-hands-on-projects/learn/lecture/9604610?start=0#overview


팩토리 디자인 패턴은 가장 많이 사용되는 생성 디자인 패턴 중 하나이다.

팩토리 메소드는 무엇인가?

팩토리 메소드 패턴을 왜 사용할까? 코드 전체에 퍼져있는 객체 생성 로직을 옮기고 싶고 개별 클래스를 캡슐화할 때 팩토리 메소드 패턴을 사용할 수 있다.

이전에 했던 심플 팩토리와 비슷하지 않나고 생각할 수도 있다. 맞는 말이지만 팩토리 메소드는 패턴에 특별한 무언가를 추가한다.

  • 코드 전체에 퍼져있는 객체 생성 로직을 옮기고 싶고 개별 클래스를 캡슐화할 때 팩토리 메소드 패턴을 사용할 수 있다. 이전에 했던 심플 팩토리와 비슷하지 않나고 생각할 수도 있다. 맞는 말이지만 팩토리 메소드는 패턴에 특별한 무언가를 추가한다.
  • 우리는 어떤 클래스에서 객체를 생성해야 할지 모르고 새로운 클래스가 추가되는 상황에서 클라이언트 코드에 영향을 주지 않고 객체 생성을 할려고 할 때 이 패턴을 사용한다. 이것은 새로운 클래스를 추가함으로써 객체를 인스턴스화할 수 있고 팩토리 메소드 패턴이 클라이언트 코드를 변경하지 않고 처리할 수 있다는 것을 의미한다.
  • 팩토리 메소드를 오버라이딩함으로써 서브클래스에서 객체생성을 한다. 그리고 서브클래스가 어느 객체를 인스턴스화 할 지 결정한다. 팩토리 메소드를 오버라이딩하여 사용한다.

UML

팩토리 메소드 구현

  • 생성자에 대한 클래스를 만들면서 시작한다.
    • 디폴트 객체를 제공한다면 생성자 자체는 구체적인 클래스가 될 수 있지만 그렇지 않으면 추상 클래스가 될 수 있다. 팩토리 메소드는 단지 서브 클래스 중 하나에서 오버라이딩 되는 메소드를 의미한다.
    • 구현부에서 메소드를 오버라이딩하고 객체를 리턴한다.

Example: UML

Message 클래스를 정의하면서 시작된다. Product 클래스가 된다. 이는 인터페이스나 기반 클래스가 되고 서브클래스 중 하나에서 이 클래스의 객체를 생성한다.

Message에 대해 두 개의 서브 클래스가 있다. TextMessage, JsonMessage가 있다. 이 서브 클래스는 메시지의 내용을 어떻게 저장하느냐에 따라 다르다.

TextMessage는 메시지를 단지 텍스트 문자열로 저장하고, 반면에 JsonMessage는 Json 포맷으로 저장을 한다.

그리고 MessageCreator가 있다. 이것은 추상 생성자이며 Product 서브클래스 중 하나를 생성하는 팩토리 메소드를 정의한다. Creator에 대한 두 개의 구현체를 가지고 있다. 하나는 JsonMessageCreator이고 팩토리를 오버라이드하며 Json 메시지를 인스턴스화 한다. 그리고 TextMessageCreator가 있고 Text 메시지를 생성한다.

Java 구현

/**
 * 이 클래스는 Message에 대한 인터페이스를 나타낸다.
 * 구현부에서 contentType을 명시할 것이다.
 */
public abstract class Message {

    public abstract String getContent();

    public void addDefaultHeaders() {
    }

    public void encrypt() {
    }
}

여기에 Message 클래스가 있고 Product 클래스이며 추상 클래스이다. 이 메시지의 서브 클래스 객체를 생성할 것이다.

public class JSONMessage extends Message {

    @Override
    public String getContent() {
        return "{\"JSON\":[]}";
    }
}

그 다음 JSONMessage가 있고 Product 클래스를 확장하는 구체 클래스이다.

public class TextMessage extends Message {

    @Override
    public String getContent() {
        return "Text";
    }
}

그리고 TextMessage가 있다.

public abstract class MessageCreator {

    public Message getMessage() {
        Message message = createMessage();
        message.addDefaultHeaders();
        message.encrypt();

        return message;
    }

    // 팩토리 메소드
    public abstract Message createMessage();
}

그리고 MessageCreator가 있고 추상 생성자이고 이것이 추상 팩토리 메소드가 된다.

추상 생성자는 보통 서브클래스에 작성된 추가적인 작업을 수행한다. 필수는 아니지만 일반적으로 추상 생성자가 동작하는 방식이다.

public class JSONMessageCreator extends MessageCreator {
    @Override
    public Message createMessage() {
        return new JSONMessage();
    }
}

이제 구체 클래스를 구현할 차례다. 구체 생성자를 구현하는건 매우 쉽다.

JsonMessageCreator이며 단지 새로운 Json을 리턴한다.

public class TextMessageCreator extends MessageCreator {
    @Override
    public Message createMessage() {
        return new TextMessage();
    }
}

비슷하게 TextMessageCreator가 있고 구체 메시지 메서드를 오버라이드하고 TextMessage를 리턴한다.

public class Client {

    public static void main(String[] args) {
        printMessage(new JSONMessageCreator());
        printMessage(new TextMessageCreator());
    }

    private static void printMessage(MessageCreator creator) {
        Message message = creator.getMessage();
        System.out.println(message.getContent());
    }
}

Client를 만들어볼 차례다. JsonMessageCreator를 만들어보고 TextMessageCreator를 만들어보자.

구현 고려사항

  • 생성자는 구체 클래스가 될 수 있고 팩토리 메소드에 기본 구현을 제공할 수도 있다. 그런 경우 기반 클래스에 디폴트 객체를 생성해야 할 것이다.
  • 또한, 다른 유형의 객체 타입을 선택할 때 추가적인 인수를 받는 심플 팩토리 패턴을 사용할 수도 있다. 서브 클래스는 특정 기준에 따라서 객체를 만드는 팩토리 메소드를 오버라이딩 할 수도 있다.

디자인 고려사항

  • 팩토리 메소드 패턴에서 생성자 구조는 product 구조를 나타낸다. 일반적으로 객체 유형 당 하나의 구체 클래스가 생성이 된다. (JSONMessageCreator, TextMessageCreator)
  • 템플릿 메소드 패턴에서 팩토리 메소드이 사용될 수도 있다.
  • 추상 클래스라고 불리는 또 다른 생성 디자인 패턴도 팩토리 메소드를 사용한다.

위험요소

  • 구현하기 복잡하다. 단위 테스트에 많은 클래스가 필요하다.
  • 처음부터 팩토리 메소드 패턴으로 시작해야 한다. 기존 코드를 팩토리 메소드 패턴으로 리팩토링 하는 것이 쉽지만은 않다.
  • 때로는 이 패턴을 사용하면 서브클래스에서 인스턴스를 반드시 인스턴스를 만들어야 한다.



반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유