Design patterns 05.

Creational pattern - Factory method

by Dichter
팩토리 메서드(Factory Method)란?

우선 에릭 감마를 비롯한 4인방이 소개하는 팩토리 메서드의 의도, 동기 그리고 활용을 읽어보자. 어렵지 않은 단어와 문장이니, 의미를 보며 정독해보자.


Intent

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.


Motivation

Frameworks use abstract classes to define and maintain relationships between objects. A framework is often responsible for creating these objects as well.


Consider a framework for applications that can present multiple documents to the user. Two key abstractions in this framework are the classes Application and Document. Both classes are abstract, and clients have to subclass them to realize their application-specific implementations. To create a drawing application, for example, we define the classes DrawingApplication and DrawingDocument. The Application class is responsible for managing Documents and will create them as required-when the user selects Open or New from a menu, for example.


Because the particular Document subclass to instantiate is application-specific, the Application class can't predict the subclass of Document to instantiate-the Application class only knows when a new document should be created, not what kind of Document to create. This creates a dilemma: The framework must instantiate classes, but it only knows about abstract classes, which it cannot instantiate.


The Factory Method pattern offers a solution. It encapsulates the knowledge of which Document subclass to create and moves this knowledge out of the framework. Application subclasses redefine an abstract CreateDocument operation on Application to return the appropriate Document subclass. Once an Application subclass is instantiated, it can then instantiate application-specific Documents without knowing their class. We call CreateDocument a factory method because it's responsible for "menufacturing" an object.


Applicability

Use the Factory Method pattern when

a class can't anticipate the class of objects it must create.

a class wants its subclasses to specify the objects it creates.

classes delegate responsibility to one of several helper subclass, and you want to localize the knowledge of which helper subclass is the delegate.


들어가기 앞서서, 팩토리 메서드는 추상 팩토리와 매우 비슷하다. 하지만 추상 팩토리에는 추상 팩토리 객체에 특정 구체 팩토리를 전달하여, 통일성 있는 객체 생성을 할 수 있게 한다. 이때 추상 팩토리는 당연하게도 특정 구체 팩토리 없이는 나홀로 객체를 생성할 수 없다. 반면 팩토리 메서드는 구체 팩토리로 시작하며, 특정 객체는 새로운 클래스로 인스턴스화 되어야 한다면, 구체 팩토리를 상속하여 그 메서드만 수정한다.


설명에서는 추상 클래스들을 사용하는 프레임워크의 예시를 들고 있다. 프레임워크는 종종 객체 생성을 담당하고 있으며, 사용자에게 인터페이스 통일을 위해 구체 클래스를 이용하기보다는 추상 클래스를 사용하여 객체를 생성하고 싶어한다.

이 프레임워크가 어플리케이션과 문서라는 추상 클래스들을 객체로 생성하고 싶은 상황을 가정해보자. 어플리케이션과 문서라는 클래스는 서로에 연관성이 깊기 때문에 동일한 범주의 구체 클래스로 생성되어야 한다. 하지만 프레임워크는 추상 클래스를 이용할 것이기에 각 생성되는 객체의 구체 클래스에 대한 정보는 알고 싶지 않다.


이 때, 팩토리 메서드가 적용된 팩토리를 이용하여, 연관성이 깊은 두 객체를 생성하는 메서드를 사용하여, 두 객체의 통일성이 보장이 된다. 팩토리는 부모 클래스로부터 상속되었으며, 두 객체를 제외한 나머지 메서드들은 부모 클래스와 동일하다.


팩토리 메서드 예제

생성 패턴을 설명하는 글에서 보여줬던 Maze 예제를 팩토리 메서드를 이용하여 리팩토링 해보자. (코드를 삽입할 수 있는 수단이 없어, GitHub 링크로 대체하였다.)

Factory method example code link


추상 팩토리와 마찬가지로 기존 Maze 코드에 새로운 요구사항이 추가된 상황이다. 기존 Maze에는 평범한 Wall, Door, Room으로 구성되어 있다. 하지만 기존 Maze 이외에도 사용자(개발자)가 선택할 수 있는 다양한 Maze를 추가하려고 한다. 마법으로만 열 수 있는 Door와 마법으로 가득 찬 Room을 생성하는 팩토리, 폭탄이 존재할 수 있는 Room을 생성하는 팩토리 등 여러 Maze 팩토리를 만들어보자.


추상 팩토리 예제를 앞서 공부했다면, 이를 구현하기 위해 추상 팩토리에서는 각 Maze 별로 팩토리를 만들어주고, 이를 이용하여 추상 팩토리가 알맞는 객체를 생성할 수 있도록 도와준다. 하지만 NormalWall과 같이 대부분 Maze 팩토리에 공통된 객체들이 존재할 경우 코드 중복이 많다. 이때 팩토리 메서드 예제와 같이 Normal 객체들을 선언해주는 구체 클래스들을 상속함하고, 자기가 수정이 필요한 메서드만 부분부분 새로 고친 Maze 구체 팩토리 클래스를 이용하여 추상 팩토리와 마찬가지로 일관성 있는 객체 생성이 가능해진다.


미켈란젤로 부오나로티피에타
바티칸 시국의 성 베드로 대성전에 보관되어 있는 르네상스 시대 조각 예술의 대표적인 명작품이다. 실제로 글쓴이가 성 베드로 대성전에서 본 피에타는 그 크기가 매우 컸다. 또한 성모 마리아에 새겨진 미켈란젤로의 서명의 일화가 기억이 남는다. 아름다운 밤 풍경에 "하느님께서도 이런 아름다운 작품에 당신의 이름을 새기지 않았는데 내가 이런 짓을 하다니"라고 깨닫고 뒷날 자신의 서명을 후회하고서 이후에 자신이 만든 작품에는 서명을 하지 않았다고 한다.


1쇄. 2020.12.07.

keyword
작가의 이전글Design patterns 04.