Conceptly
← 전체 목록
🏭

Factory Method

생성객체 생성을 서브클래스에 위임하는 생성 패턴

Factory Method는 객체를 생성하는 코드를 직접 쓰는 대신, 생성 책임을 서브클래스에 넘기는 생성 패턴입니다. 상위 클래스(Creator)는 '무엇을 만들지'의 인터페이스만 정의하고, 실제로 '어떤 구체 객체를 만들지'는 하위 클래스(ConcreteCreator)가 결정합니다. 클라이언트는 Product 인터페이스에만 의존하므로 구체 클래스가 바뀌어도 호출 코드는 바뀌지 않습니다.

아키텍처 다이어그램

🔍 구조 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

코드에서 new ConcreteClass()를 직접 쓰면 그 클래스에 대한 의존이 콘크리트로 박힙니다. 처음에는 괜찮지만, 나중에 같은 역할을 하는 다른 구현이 필요해지면 문제가 시작됩니다. 예를 들어, 알림을 보내는 기능을 만들 때 처음에는 이메일만 있어서 new EmailNotifier()를 직접 쓰다가, 나중에 SMS, 푸시 알림이 추가되면 이 생성 코드가 곳곳에 퍼져 있어 하나하나 찾아 수정해야 합니다. if-else나 switch로 타입을 분기하면 새 타입이 추가될 때마다 분기를 늘려야 하고, 분기가 늘어날수록 변경 범위가 걷잡을 수 없이 퍼집니다. 핵심은 '어떤 객체를 만드느냐'가 바뀔 때마다 그 객체를 사용하는 쪽까지 함께 고쳐야 하는 결합 구조입니다.

왜 이런 방식이 등장했나요?

객체지향 프로그래밍이 산업 전반에 자리 잡던 1990년대 초반, 재사용 가능한 프레임워크를 만드는 일이 중요한 과제였습니다. 프레임워크는 전체 흐름을 정해 두되, 구체적인 동작은 사용자가 채워 넣을 수 있어야 했습니다. 그런데 프레임워크 안에서 new를 직접 호출하면 특정 구현에 묶이고, 사용자가 자기만의 객체로 교체하기 어려워졌습니다. GoF는 이 문제를 '생성을 메서드로 분리하고, 서브클래스가 그 메서드를 오버라이드하게 하자'는 아이디어로 풀었습니다. 프레임워크는 추상 메서드만 호출하고, 구체 생성은 프레임워크를 확장한 쪽이 담당합니다. 이 방식은 이후 Java, C#, Python 등 거의 모든 객체지향 언어의 표준 라이브러리와 프레임워크에 녹아들었습니다.

내부적으로 어떻게 동작하나요?

Factory Method의 핵심은 '만드는 행위'를 별도의 메서드로 빼는 데 있습니다. 먼저 Product 인터페이스가 있습니다. 생성될 객체들이 공통으로 따르는 계약입니다. 클라이언트가 의존하는 건 이 인터페이스뿐입니다. 다음으로 Creator 클래스가 있습니다. 이 클래스는 createProduct() 같은 팩토리 메서드를 선언합니다. Creator는 이 메서드의 반환 타입만 Product 인터페이스로 지정할 뿐, 안에서 뭘 만들지는 비워 둡니다. 마지막으로 ConcreteCreator가 이 메서드를 오버라이드해서 구체적인 ConcreteProduct를 생성합니다. ConcreteCreatorA는 ProductA를, ConcreteCreatorB는 ProductB를 돌려줍니다. 클라이언트 코드는 Creator 타입으로 받아서 createProduct()를 호출하기만 하면 됩니다. 어떤 ConcreteCreator가 들어오느냐에 따라 다른 Product가 만들어지지만, 클라이언트는 그 차이를 알 필요가 없습니다.

무엇과 헷갈리나요?

Factory Method와 Abstract Factory는 둘 다 객체 생성을 추상화한다는 점에서 비슷하지만, 규모가 다릅니다. Factory Method는 메서드 하나가 객체 하나를 만드는 단위이고, Abstract Factory는 관련된 객체 묶음(제품군)을 한꺼번에 만드는 인터페이스입니다. 버튼 하나만 플랫폼별로 바꾸면 되는 상황에는 Factory Method가 맞고, 버튼·텍스트필드·체크박스를 세트로 묶어 플랫폼별로 교체해야 한다면 Abstract Factory 쪽이 자연스럽습니다. Factory Method와 단순 팩토리(Simple Factory)도 혼동되기 쉽습니다. Simple Factory는 if-else로 분기해 객체를 만드는 정적 메서드일 뿐, 디자인 패턴이라기보다 관용 기법에 가깝습니다. Factory Method는 상속과 오버라이드로 생성을 위임하기 때문에 새 타입을 추가할 때 기존 코드를 건드리지 않아도 됩니다.

언제 쓰나요?

Factory Method가 등장하는 전형적인 신호는 '같은 역할을 하지만 구현이 다른 객체를 상황에 따라 바꿔 만들어야 하는 코드'입니다. 로그를 파일에 쓸지 콘솔에 쓸지, 알림을 이메일로 보낼지 푸시로 보낼지, 결제를 카드로 할지 계좌이체로 할지 — 이런 분기가 여러 곳에 퍼져 있다면 Factory Method로 생성 지점을 한곳에 모으는 걸 고려할 수 있습니다. 프레임워크나 라이브러리를 설계할 때도 유용합니다. 프레임워크가 전체 흐름을 잡되, 흐름 안에서 쓰이는 구체 객체는 사용자가 결정하게 해야 할 때 Factory Method를 두면 확장 포인트가 명확해집니다. 다만 타입이 하나밖에 없고 바뀔 가능성이 낮다면 Factory Method는 과도한 추상화입니다. 클래스가 불필요하게 늘어나고 코드를 따라가기 어려워지기만 합니다. 변경이 실제로 일어나는 축에만 적용하는 게 핵심입니다.

UI 프레임워크문서 처리로깅 시스템데이터 접근