팩토리 메서드 (Factory Method)
객체 생성의 책임을 하위클래스에 위임하는 패턴
팩토리 메소드 패턴(Factory Method Pattern)은 객체 생성을 캡슐화하여, 하위클래스에서 객체의 생성 방식을 결정하도록 하는 디자인 패턴입니다. 즉, 객체를 직접 생성하는 것이 아니라, 객체 생성을 담당하는 메소드를 통해 객체를 반환하도록 합니다. 이 패턴을 활용하면 클라이언트 코드가 특정 클래스의 인스턴스를 직접 생성하지 않고, 추상화된 인터페이스를 통해 객체를 생성할 수 있습니다.
팩토리 패턴과 팩토리 메서드 패턴은 어떻게 다를까?
둘 다 객체 생성을 캡슐화하는 디자인 패턴이지만, 그 방식과 의도에서 차이가 있습니다.
팩토리 패턴
객체 생성을 직접 수행하는 것이 아니라, 객체 생성을 담당하는 별도의 클래스(팩토리 클래스)를 두고, 이를 통해 객체를 생성하는 방식입니다. 즉, 객체 생성 로직을 클라이언트 코드에서 분리하여 관리하는 것입니다. 주로 단순한 객체 생성을 중앙 집중화할 때 유용합니다.
User
라는 엔티티와 DTO를 만들어보겠습니다.
이제 User
엔티티 말고, 소셜 로그인 인터페이스를 통해 다양한 제 3자 로그인을 구현해보겠습니다. 하나의 객체 생성이 아니라 다양한 객체 생성이 필요하겠죠? 팩토리 패턴을 활용해서 SocialLoginFactory
를 구현해보겠습니다. 어떤 문제가 있는지 같이 확인해봐요!
추가 소셜로그인 기능이 생긴다면 기존 코드를 수정해야하는 문제점이 생깁니다. 이때 팩토리 메서드 패턴을 활용할 수 있겠습니다.
팩토리 메서드 패턴
팩토리 메서드는 객체 생성을 위한 인터페이스(추상 메서드)를 정의하고, 하위 클래스가 이를 구현하여 객체를 생성하도록 하는 방식입니다. 즉, 객체 생성을 하위 클래스에서 결정하도록 유도하여, 개방-폐쇄 원칙(OCP)을 따르게 합니다. 이렇게 되면 확장 가능성이 높아 새로운 객체 타입을 추가하기 쉽습니다.
소셜 로그인 인터페이스와 소셜 로그인 팩토리 추상클래스를 통해 다양한 제 3자 로그인을 구현해보겠습니다.
객체 생성 책임
하나의 팩토리 클래스가 생성 책임을 가짐
하위클래스에서 객체 생성 로직을 결정
유연성
새로운 객체 유형 추가 시 기존 팩토리 클래스 수정 필요
새로운 하위클래스를 추가하여 확장 가능 (OCP 준수)
설계 방식
단순한 정적 메서드 또는 별도의 팩토리 클래스를 사용
상속을 활용해 객체 생성 방식을 변경
사용 예
단순한 객체 생성을 중앙 집중화할 때
다양한 객체 생성을 하위클래스에 위임할 때
주요 특징
객체 생성 로직을 캡슐화 → 객체 생성을 직접 하지 않고, 팩토리 메소드를 통해 생성
유연한 확장성 → 새로운 객체 타입이 추가되더라도 기존 코드 수정 없이 확장 가능
결합도 낮추기 → 클라이언트 코드가 구체적인 클래스를 몰라도 객체를 생성할 수 있도록 유도
언제 활용할 수 있을까?
싱글톤 패턴에 비해 팩토리 메서드 패턴을 언제 활용할 수 있을지 이해하는 것이 어려웠습니다. 하지만 비슷한 객체를 반복적으로(공장처럼) 생성해야 할 경우에 팩토리 메서드 패턴 사용을 고려해본다고 생각하니 이해가 쉬워졌습니다. 또 개발자가 컴파일 단계에서 어떤 객체를 생성해야할 지 모르고, 런타임 단계에서 동적으로 객체를 생성해야 할 때도 사용할 수 있습니다.
팩토리 메서드 패턴과 추상 팩토리 패턴은 어떻게 다를까?
팩토리 메소드 패턴은 종종 추상 팩토리 패턴(Abstract Factory Pattern)과 함께 사용됩니다.
팩토리 메소드를 추상 클래스로 정의하여 각 팩토리마다 독립적인 생성 방식 유지할 수 있습니다. 클라이언트 코드가 특정 팩토리 인스턴스를 선택하여 사용할 수 있도록 유도합니다.
패턴 유형
생성 패턴
생성 패턴
목적
하나의 객체를 생성하는 팩토리 메서드를 제공
관련된 여러 객체군(Family)을 생성하는 팩토리를 제공
구성
단일 객체 생성을 위한 하위 클래스에서 팩토리 메서드를 구현
여러 객체를 생성하는 팩토리 클래스 자체를 추상화
확장성
새로운 객체 유형을 추가하려면 기존 팩토리 메서드를 수정해야 함
새로운 객체군을 추가할 때 기존 팩토리를 수정할 필요 없음
유지보수
상대적으로 단순한 구조
보다 복잡한 구조지만 유지보수성이 높음
사용 사례
특정 인터페이스를 가진 객체를 동적으로 생성해야 할 때
특정 제품군(예: UI 컴포넌트, 데이터베이스 등)을 그룹화하여 생성할 때
예제
ButtonFactory → Button (WindowsButton, MacOSButton)
UIFactory → Button, Checkbox (WindowsUIFactory, MacOSUIFactory)
팩토리 메서드 패턴의 장점
객체 생성 로직을 분리하여 코드 가독성 향상
클라이언트 코드의 결합도 낮추기 (Loose Coupling)
새로운 객체 타입을 쉽게 추가하여 확장성 증가
팩토리 메서드 패턴의 단점
각 제품 구현체마다 팩토리 객체들을 모두 구현해주어야 하기 때문에, 구현체가 늘어날때 마다 팩토리 클래스가 증가하여 서브 클래스 수가 폭발합니다.
코드가 매우 복잡해질 수 있습니다.
단순한 객체 생성에는 오버헤드가 발생할 수 있습니다. (단순한 객체는 new 키워드 사용이 더 적합)
정리
핵심 개념
객체 생성을 위한 단순한 팩토리 함수 또는 클래스
객체 생성을 위한 하위클래스에서 구현해야 하는 메서드 제공
서로 연관된 객체 그룹을 생성하는 팩토리 제공
구성 요소
팩토리 클래스 또는 함수
제품 객체
팩토리 클래스를 부모로 두고, 하위 클래스에서 구현
서브클래스에서
create()
를 구현
여러 개의 팩토리 메서드를 포함한 팩토리 클래스
여러 개의 제품이 생성됨
사용 목적
단순한 객체 생성 방식 제공
객체 생성을 하위클래스에서 결정하도록 강제
제품 계열(Family)을 함께 생성
확장성
새로운 제품을 추가할 때 팩토리 로직 수정 필요
새로운 제품을 추가할 때 새로운 하위 클래스 추가
새로운 제품군을 추가할 때 새로운 팩토리 추가
예제
ButtonFactory.createButton("Windows")
WindowsButtonFactory.createButton()
WindowsUIFactory.createButton()
, WindowsUIFactory.createCheckbox()
팩토리 메소드 패턴은 객체 생성 로직을 캡슐화하고, 유연한 확장을 가능하게 합니다. 다양한 프레임워크와 라이브러리에서 널리 사용되므로, 실제 프로젝트에서 적절히 활용하면 보다 유지보수성이 높은 코드를 작성할 수 있습니다. 여러분은 어떤 사례에서 팩토리 메소드 패턴을 활용해 보셨나요? 😊
참고 자료
Last updated
❌ 모든 로그인 객체를 관리하는 SocialLoginFactory 구현
현재
SocialLoginFactory
클래스는 타입에 따라KakaoLogin
객체 생성을, 때론 다른 객체 생성을 합니다. 그래서 OOP의 단일책임원칙에 어긋나고 있습니다. 뿐만 아니라 깃허브 로그인이 추가된다면, 기존 코드에 case 문을 추가해서 생성해야하는 개방-폐쇄 원칙을 위배하고 있습니다.