[디자인 패턴][생성 패턴] 추상 팩토리 패턴(Abstract Factory Pattern)
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. 특징
-
구체 클래스의 분리 : 클라이언트가 인터페이스에 의존하게 되므로 결합도가 낮아지고, 기존 코드의 수정 없이 기능의 확장이 가능
-
기능의 일관성 향상 : 함께 생성해야 하는 객체들의 그룹을 만들어줌으로써 항상 유형별로 동일한 기능 제공 가능
-
새로운 기능 추가의 어려움 : 추상 팩토리에 새로운 기능을 정의하는 경우 추상 팩토리를 상속받는 클래스들의 코드 변경이 필요
Leave a comment