Motivation
현대 개발에서 Modulzation은 중요한 이슈이다. 더욱 General한 정보를 캡슐화 하기 위해 코드를 추가하는 것은 맘에 들지 않는다. 전화 번호를 다루는 Information Manager를 생각해보자. 전화번호는 지역, 국가별로 생성 규칙이 다르다. 여러 국가를 지원하기 위한 코드를 작성하다보면 코드는 계속해서 복잡해 질 것이다.
추상팩토리패턴은 이 상황에서 적용 될 수 있다. 일반적인 전화번호의 로직을 담은 Abstract Factory 는 하나의 Framework로서 제공되며 구체 국가에 따른 전화번호는 Concrete Factory로써 제공된다. 이들은 런타임에 쌍을 이루어 사용될 수 있다.
즉, Abstract Factory는 Concrete Factory를 생성하기 위한 일종의 super-factory이다. (Factory of factories)
Intent
추상 팩토리는 연관된 객체 그룹들을 생성하는 팩토리를 생성하는 인터페이스를 구체 클래스에 대한 의존 없이 제공한다.
Implementation

AbstractFactory
- 팩토리의 팩토리
ConcreteFactory
- 구체 Product를 만드는 팩토리
AbstractProduct
- Product 타입의 인터페이스
Product
- 팩토리에서 찍어낸 제품
Client
- AbstractFactory와 AbstractProduct의 sub-class 들을 활용함
Class Implementation
abstract class AbstractProductA{ public abstract void operationA1(); public abstract void operationA2(); } class ProductA1 extends AbstractProductA{ ProductA1(String arg){ System.out.println("Hello "+arg); } // Implement the code here public void operationA1() { }; public void operationA2() { }; } class ProductA2 extends AbstractProductA{ ProductA2(String arg){ System.out.println("Hello "+arg); } // Implement the code here public void operationA1() { }; public void operationA2() { }; } abstract class AbstractProductB{ //public abstract void operationB1(); //public abstract void operationB2(); } class ProductB1 extends AbstractProductB{ ProductB1(String arg){ System.out.println("Hello "+arg); } // Implement the code here } class ProductB2 extends AbstractProductB{ ProductB2(String arg){ System.out.println("Hello "+arg); } // Implement the code here } abstract class AbstractFactory{ abstract AbstractProductA createProductA(); abstract AbstractProductB createProductB(); } class ConcreteFactory1 extends AbstractFactory{ AbstractProductA createProductA(){ return new ProductA1("ProductA1"); } AbstractProductB createProductB(){ return new ProductB1("ProductB1"); } } class ConcreteFactory2 extends AbstractFactory{ AbstractProductA createProductA(){ return new ProductA2("ProductA2"); } AbstractProductB createProductB(){ return new ProductB2("ProductB2"); } } //Factory creator - an indirect way of instantiating the factories class FactoryMaker{ private static AbstractFactory pf=null; static AbstractFactory getFactory(String choice){ if(choice.equals("1")){ pf=new ConcreteFactory1(); }else if(choice.equals("2")){ pf=new ConcreteFactory2(); } return pf; } } // Client public class Client{ public static void main(String args[]){ AbstractFactory pf=FactoryMaker.getFactory("1"); AbstractProductA product=pf.createProductA(); //more function calls on product } }
Factory의 구체 클래스를 변경하는 것 만으로 간단하게 공장을
1번 A제품, 1번 B제품을 찍어내는 공장
ConcreteFactory1
에서2번 A제품, 2번 B제품을 찍어내는 공장
ConcreteFactory2
로 바꿀 수 있다.Applicability & Examples
이럴때 추상 팩토리 패턴을 사용합니다!
- 공장에서 찍어낼 제품의 로직과 생성로직이 독립적이어야 하는 경우
- 시스템이 여러 제품군의 그룹을 가지며 그들을 Flexible하게 Configure할 필요가 있는 경우
- 제품의 그룹이 함께 동작해야 하는 경우 (e.g. 1번 A 제품 + 1번 B 제품)
- 제품의 그룹의 생성에 대한 라이브러리 (인터페이스)제공이 필요한 경우
Phone Number Examples
예를 들어 여러 국적을 가질 수 있는
User
라는 클래스에 PhoneNumber
와 Address
정보가 포함 되기를 원하는 경우 UserFactory
를 추상 팩토리로 하여 두 구체 팩토리 클래스를 아래와 같이 조합하여 사용할 수 있습니다.UsaUserFactory
= UsaPhoneNumberFactory
+ UsaAddressFactory
KoreanUserFactory
= KoreanPhoneNumberFactory
+ KoreanAddressFactory
Look & Feel Example
사용자의 접속 경로에 따라 다른 GUI를 노출해야 하는 경우도 추상 팩토리 패턴의 좋은 적용 사례이다.

Specific problems
장점
- 클라이언트에게 생성로직을 분리
- 제품군을 변경하기 쉽다.
- 제품군이 함께 동작해야하는 경우 로직을 표현하기 쉽다.
단점
- 공장이 한번 만들어지면 제품군을 수정하기 어렵다.
- 예를 들어 위 GUI 예시에서 제품군에 SideBar를 새로운 제품군으로 추가하고자 한다면 모든 fatories와 AbstractFactory에 createSideBar 메서드가 추가되어야한다.
- 코드의 변경을 최소화 하기 위해서는 상속이 필요하다.
Implementation
Factories as singletones
일반적으로 애플리케이션은 한 제품군에 대한 One and Only One - Singleton 구체 팩토리 클래스 (공장)을 필요한다.
Creating the products
추상 팩토리 (공장의 공장)는 공장을 찍어내는 역할에 Interface만 한다. 제품을 찍어내는 것은 구체 클래스(공장)이다.
비슷한 역할을 하는 디자인 패턴으로 Prototype design pattern이 있다.
Extending the factories
새로운 제품을 찍어내기 위해 모든 코드를 갈아없는 짓은 하고 싶지 않다. 특정 공장만 상속해서 그 제품을 추가하는 것은 간단하지만 공장들 끼리 서로 다른 Interface를 가지게 되므로 안전하지는 않다.