Updated:

1. 개요

서로 관련성이 있거나 독립적인 여러 객체들의 조합을 만들기 위한 인터페이스를 제공하는 패턴

추상 팩토리 패턴(Abstract Factory Pattern)은 생성 패턴(Creational Pattern)의 한 종류로, 서로 관련성이 있거나 독립적인 여러 객체들의 조합을 만들기 위한 인터페이스를 제공하는 패턴이다. 단순히 객체를 만들어 주는 것이 아니라 객체들의 조합을 만들어 준다는 점이 중요하다.

2. 생성 패턴(Creational Pattern)

2-1. 생성 패턴이란?

생성 패턴이란 인스턴스를 만드는 절차를 추상화하는 패턴으로, 객체를 생성, 합성하는 방법이나 객체의 표현 방법과 시스템을 분리해 준다. 생성 패턴은 아래 두 가지 특징으로 인해 무엇이, 어떻게, 언제 생성되는지 결정하는데 유연성을 확보할 수 있다.

  • 시스템이 어떤 구체 클래스를 사용하는지에 대한 정보를 캡슐화 한다.

  • 인스턴스들이 어떻게 만들고, 결합하는지에 대한 부분을 완전히 가려준다.

2-2. 생성 패턴 종류

3. 구성

[출처 : GoF의 디자인 패턴]

  • AbstractFactory : 프로그램의 객체를 생성해주는 메서드를 가진 인터페이스

  • ConcreteFactory : 그룹별 필요한 객체들을 생성

  • AbstractProduct : 공통 기능을 정의해 놓은 인터페이스

  • ConcreteProduct : AbstractProduct가 정의한 메서드 구현

  • Client : AbstractFactory, AbstractProduct 인터페이스의 메서드만 사용

4. 예제 코드

Windows와 Mac에서 동작하는 문서 편집기를 개발한다고 가정해보자. OS마다 단축키도 다르고, 메뉴 버튼의 UI도 다를 것이다. 문서 편집기를 추상화 한 인터페이스(AbstractFactory)를 생성하고, 인터페이스를 구현하는 클래스(ConcreteFactory)를 통해 각각의 OS에서 사용되는 객체들을 생성한다.

4-1. AbstractProduct

[Shortcut.java]

1
2
3
4
5
public interface Shortcut {

    String copy();
    String paste();
}

[Menu.java]

1
2
3
4
public interface Menu {

    String save();
}

4-2. ConcreteProduct

[WindowsShortcut.java]

1
2
3
4
5
6
7
8
9
10
11
12
public class WindowsShortcut implements Shortcut {

    @Override
    public String copy() {
        return "Windows Copy";
    }

    @Override
    public String paste() {
        return "Windows Paste";
    }
}

[MacShortcut.java]

1
2
3
4
5
6
7
8
9
10
11
12
public class MacShortcut implements Shortcut {

    @Override
    public String copy() {
        return "Mac Copy";
    }

    @Override
    public String paste() {
        return "Mac Paste";
    }
}

[WindowsMenu.java]

1
2
3
4
5
6
7
public class WindowsMenu implements Menu {

    @Override
    public String save() {
        return "Windows Save";
    }
}

[MacMenu.java]

1
2
3
4
5
6
7
public class MacMenu implements Menu {

    @Override
    public String save() {
        return "Mac Save";
    }
}

4-3. AbstractFactory

[Editor.java]

1
2
3
4
5
public interface Editor {

    Shortcut createShortCut();
    Menu createMenu();
}

4-4. ConcreteFactory

[WindowsEditor.java]

1
2
3
4
5
6
7
8
9
10
11
12
public class WindowsEditor implements Editor {

    @Override
    public Shortcut createShortCut() {
        return new WindowsShortcut();
    }

    @Override
    public Menu createMenu() {
        return new WindowsMenu();
    }
}

[MacEditor.java]

1
2
3
4
5
6
7
8
9
10
11
12
public class MacEditor implements Editor {

    @Override
    public Shortcut createShortCut() {
        return new MacShortcut();
    }

    @Override
    public Menu createMenu() {
        return new MacMenu();
    }
}

5. 테스트

실제로는 의존성 주입을 통해 런타임 시점에 구체 클래스가 정해지도록 하여 클라이언트가 어떤 구체 클래스를 사용할지 몰라야 한다. 하지만 테스트를 위해 구체 클래스를 직접 사용하여 실행 결과를 확인해보도록 하자.

[Client.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Client {

    public static void main(String[] args) {
        Editor windowsEditor = new WindowsEditor();
        System.out.println("Copy : " + windowsEditor.createShortCut().copy());
        System.out.println("Paste : " + windowsEditor.createShortCut().paste());
        System.out.println("Save : " + windowsEditor.createMenu().save());
        System.out.println("--------------------");
        Editor macEditor = new MacEditor();
        System.out.println("Copy : " + macEditor.createShortCut().copy());
        System.out.println("Paste : " + macEditor.createShortCut().paste());
        System.out.println("Save : " + macEditor.createMenu().save());
    }
}

[실행 결과]

6. 특징

  • 구체 클래스의 분리 : 클라이언트가 인터페이스에 의존하게 되므로 결합도가 낮아지고, 기존 코드의 수정 없이 기능의 확장이 가능

  • 기능의 일관성 향상 : 함께 생성해야 하는 객체들의 그룹을 만들어줌으로써 항상 유형별로 동일한 기능 제공 가능

  • 새로운 기능 추가의 어려움 : 추상 팩토리에 새로운 기능을 정의하는 경우 추상 팩토리를 상속받는 클래스들의 코드 변경이 필요

Updated:

Leave a comment