맨위로가기

추상 팩토리 패턴

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

추상 팩토리 패턴은 구체적인 클래스를 지정하지 않고도 관련되거나 종속된 객체 집합을 생성하는 인터페이스를 제공하는 디자인 패턴이다. 이 패턴은 객체 생성과 사용을 분리하여, 클라이언트가 객체의 구체적인 유형을 알 필요 없이 추상적인 인터페이스를 통해 객체를 사용할 수 있게 한다. 팩토리는 객체의 구체적인 유형을 결정하고, 팩토리 메서드 패턴과 관련이 있으며, DOM API와 같은 다양한 응용 분야에서 활용된다.

더 읽어볼만한 페이지

  • 소프트웨어 디자인 패턴 - 모델-뷰-컨트롤러
    모델-뷰-컨트롤러(MVC)는 소프트웨어 디자인 패턴으로, 응용 프로그램을 모델, 뷰, 컨트롤러 세 가지 요소로 분리하여 개발하며, 사용자 인터페이스 개발에서 데이터, 표현 방식, 사용자 입력 처리를 분리해 유지보수성과 확장성을 높이는 데 기여한다.
  • 소프트웨어 디자인 패턴 - 스케줄링 (컴퓨팅)
    스케줄링은 운영 체제가 시스템의 목적과 환경에 맞춰 작업을 관리하는 기법으로, 장기, 중기, 단기 스케줄러를 통해 프로세스를 선택하며, CPU 사용률, 처리량 등을 기준으로 평가하고, FCFS, SJF, RR 등의 알고리즘을 사용한다.
추상 팩토리 패턴
개요
유형생성 디자인 패턴
목적인터페이스를 변경하지 않고 관련/종속 객체의 제품군을 생성하기 위한 인터페이스 제공
별칭키트
해결특정 제품군에 대한 구체적인 클래스를 선택하여 런타임 시 객체 생성 문제 해결
추상 팩토리추상 제품 객체를 생성하는 연산을 선언하는 인터페이스
구체 팩토리추상 팩토리에 의해 선언된 객체 생성 연산을 구현
추상 제품제품 객체에 대한 인터페이스 선언
구체 제품특정 팩토리에 의해 생성된 제품 객체를 정의
클라이언트추상 팩토리 및 제품 클래스에 선언된 인터페이스를 통해 객체와 상호 작용
협업일반적으로 시스템에는 하나의 ConcreteFactory 클래스의 인스턴스만 필요
사용ui 툴킷
데이터베이스 독립적인 api
이식성 있는 애플리케이션
관련 패턴추상 팩토리는 종종 싱글톤으로 구현될 수 있음
팩토리 메서드는 추상 팩토리에 의해 정의된 생성 연산을 구현하는 데 자주 사용
추상 팩토리는 프로토타입을 사용하여 제품 객체를 복제할 수도 있음
UML 다이어그램
추상 팩토리 uml 클래스 다이어그램
추상 팩토리 uml 클래스 다이어그램

2. 구조

frame






추상 팩토리 디자인 패턴은 1994년 서적 ''디자인 패턴''에 설명된 23가지 패턴 중 하나이다.[3] 팩토리는 객체가 생성되는 코드 내의 구체적인 클래스의 위치이다. 이 패턴은 객체의 생성 방식을 사용 방식으로부터 분리하고 구체적인 클래스에 의존하지 않고 관련 객체 집합을 생성하는 것을 목표로 한다.[2] 이를 통해 기저 클래스를 사용하는 코드를 변경하지 않고도 새로운 파생 형식을 도입할 수 있다.

객체 생성을 별도의 (팩토리) 객체에 캡슐화하고, 객체를 직접 생성하는 대신 팩토리 객체에 객체 생성을 위임함으로써 클래스는 객체 생성 방식에 독립적이게 된다. 클래스는 객체를 생성하는 데 사용하는 팩토리 객체로 구성될 수 있으며, 팩토리 객체는 런타임에 교환될 수 있다.

2. 1. UML 클래스 다이어그램



위의 UML 클래스 다이어그램에서, `ProductA`와 `ProductB` 객체를 필요로 하는 `Client` 클래스는 `ProductA1` 및 `ProductB1` 클래스를 직접 인스턴스화하지 않는다. 대신 `Client`는 객체 생성(어떤 구체적인 클래스가 인스턴스화되는지)과 무관하게 `Client`를 만드는 `AbstractFactory` 인터페이스를 참조한다. `Factory1` 클래스는 `ProductA1` 및 `ProductB1` 클래스를 인스턴스화하여 `AbstractFactory` 인터페이스를 구현한다.[7]

2. 2. Lepus3 차트

추상 팩토리 패턴을 표현하는 다이어그램

3. 정의

디자인 패턴에서는 추상 팩토리 패턴을 "구체적인 클래스를 지정하지 않고도 관련되거나 종속된 객체 집합을 생성하기 위한 인터페이스"로 정의한다.[4]

4. 활용 및 응용 사례

추상 팩토리 패턴은 다양한 실제 프로그래밍 환경에서 활용된다. 1994년 디자인 패턴 서적에 소개된 23가지 패턴 중 하나로, 다음과 같은 문제를 해결하는 데 사용된다.[3]


  • 응용 프로그램과 클래스가 객체 생성 방식에 독립적일 수 있도록 한다.
  • 관련되거나 종속적인 객체 집합을 생성할 수 있도록 한다.


객체를 직접 생성하면 클래스가 특정 객체에 고정되어 유연성이 떨어진다. 팩토리는 객체 생성 코드를 분리하고, 구체적인 클래스에 의존하지 않고 관련 객체 집합을 생성한다.[2] 이를 통해 새로운 파생 형식을 쉽게 도입할 수 있다.

이 패턴은 객체 생성을 별도의 팩토리 객체에 캡슐화하고, 팩토리 객체에 객체 생성을 위임한다. 이를 통해 클래스는 객체 생성 방식에 독립적이며, 팩토리 객체는 런타임에 교환 가능하다.

팩토리는 생성될 객체의 구체적인 유형을 결정하고 객체를 생성하지만, 추상 형식의 참조 또는 포인터만 반환한다. 클라이언트는 팩토리 객체에 추상 형식의 객체 생성을 요청하고 추상 포인터를 받는다.[5]

클라이언트 코드는 구체적인 유형에 대한 지식 없이 추상 형식만 처리한다. 새로운 유형을 추가하려면 클라이언트 코드에서 다른 팩토리를 사용하도록 한 줄만 수정하면 된다. 모든 팩토리 객체가 싱글톤 객체에 저장되고 클라이언트 코드가 싱글톤을 통해 팩토리에 접근하는 경우, 팩토리 변경은 싱글톤 객체만 변경하면 된다.[6]

문서 객체 모델(DOM)은 추상 팩토리 패턴을 응용한 API 가운데 하나이다.[5]

역할해당 요소
AbstractFactoryorg.w3c.dom.Document
AbstractFactory#createProduct()org.w3c.dom.Document#createElement(String), org.w3c.dom.Document#createTextNode(String) 등
Productorg.w3c.dom.Element, org.w3c.dom.Text 등


4. 1. 프로그래밍 언어별 예제

추상 팩토리 패턴은 구체적인 클래스에 의존하지 않고 서로 관련되거나 의존적인 객체들의 집합을 생성하는 인터페이스를 제공하는 디자인 패턴이다. 여러 프로그래밍 언어에서 이 패턴이 어떻게 구현되는지 살펴보자.

각 예제에서는 공통적으로 `GUIFactory` 인터페이스와 `Button` 인터페이스(또는 추상 클래스)가 사용된다. `GUIFactory`는 버튼을 생성하는 `CreateButton` 메서드를 정의하고, `Button`은 `Paint` 메서드를 정의한다. `WinFactory`, `OSXFactory` 등은 `GUIFactory`를 구현하여 각 운영체제에 맞는 버튼을 생성한다. `WinButton`, `OSXButton` 등은 `Button`을 구현(또는 상속)하여 각 운영체제에 맞는 스타일로 버튼을 그린다. (C#, Golang, Python, PHP 예제는 하위 섹션에서 자세히 다룬다.)

C++의 경우, 다른 구현 방식을 보여준다. `MazeFactory` 클래스는 미로를 구성하는 `Maze`, `Wall`, `Room`, `Door` 객체를 생성하는 메서드들을 제공한다. `MazeGame` 클래스의 `createMaze` 메서드는 `MazeFactory`를 이용하여 미로를 생성한다. 아래는 C++ 코드 예제이다.

```c++

#include

enum Direction {North, South, East, West};

class MapSite {

public:

virtual void enter() = 0;

virtual ~MapSite() = default;

};

class Room : public MapSite {

public:

Room() :roomNumber(0) {}

Room(int n) :roomNumber(n) {}

void setSide(Direction d, MapSite* ms) {

std::cout << "Room::setSide " << d << ' ' << ms << '\n';

}

virtual void enter() {}

Room(const Room&) = delete;

Room& operator=(const Room&) = delete;

private:

int roomNumber;

};

class Wall : public MapSite {

public:

Wall() {}

virtual void enter() {}

};

class Door : public MapSite {

public:

Door(Room* r1 = nullptr, Room* r2 = nullptr)

:room1(r1), room2(r2) {}

virtual void enter() {}

Door(const Door&) = delete;

Door& operator=(const Door&) = delete;

private:

Room* room1;

Room* room2;

};

class Maze {

public:

void addRoom(Room* r) {

std::cout << "Maze::addRoom " << r << '\n';

}

Room* roomNo(int) const {

return nullptr;

}

};

class MazeFactory {

public:

MazeFactory() = default;

virtual ~MazeFactory() = default;

virtual Maze* makeMaze() const {

return new Maze;

}

virtual Wall* makeWall() const {

return new Wall;

}

virtual Room* makeRoom(int n) const {

return new Room(n);

}

virtual Door* makeDoor(Room* r1, Room* r2) const {

return new Door(r1, r2);

}

};

class MazeGame {

public:

Maze* createMaze(MazeFactory& factory) {

Maze* aMaze = factory.makeMaze();

Room* r1 = factory.makeRoom(1);

Room* r2 = factory.makeRoom(2);

Door* aDoor = factory.makeDoor(r1, r2);

aMaze->addRoom(r1);

aMaze->addRoom(r2);

r1->setSide(North, factory.makeWall());

r1->setSide(East, aDoor);

r1->setSide(South, factory.makeWall());

r1->setSide(West, factory.makeWall());

r2->setSide(North, factory.makeWall());

r2->setSide(East, factory.makeWall());

r2->setSide(South, factory.makeWall());

r2->setSide(West, aDoor);

return aMaze;

}

};

int main() {

MazeGame game;

MazeFactory factory;

game.createMaze(factory);

}

4. 1. 1. C# 예제

csharp

interface IButton

{

void Paint();

}

interface IGUIFactory

{

IButton CreateButton();

}

class WinFactory : IGUIFactory

{

public IButton CreateButton()

{

return new WinButton();

}

}

class OSXFactory : IGUIFactory

{

public IButton CreateButton()

{

return new OSXButton();

}

}

class WinButton : IButton

{

public void Paint()

{

// 윈도우 스타일로 버튼을 그린다.

}

}

class OSXButton : IButton

{

public void Paint()

{

// 맥 OS X 스타일로 버튼을 그린다.

}

}

class Program

{

static void Main()

{

var appearance = Settings.Appearance;

IGUIFactory factory;

switch (appearance)

{

case Appearance.Win:

factory = new WinFactory();

break;

case Appearance.OSX:

factory = new OSXFactory();

break;

default:

throw new System.NotImplementedException();

}

var button = factory.CreateButton();

button.Paint();

}

}

4. 1. 2. Golang 예제

go

package main

import (

"fmt"

)

type Button interface {

Paint()

}

type GUIFactory interface {

CreateButton() Button

}

type WinFactory struct{}

func (f *WinFactory) CreateButton() Button {

return new(WinButton)

}

type OSXFactory struct{}

func (f *OSXFactory) CreateButton() Button {

return new(OSXButton)

}

type LinuxFactory struct{}

func (f *LinuxFactory) CreateButton() Button {

return new(LinuxButton)

}

type WinButton struct{}

func (b *WinButton) Paint() {

fmt.Println("WinButton")

}

type OSXButton struct{}

func (b *OSXButton) Paint() {

fmt.Println("OSXButton")

}

type LinuxButton struct{}

func (b *LinuxButton) Paint() {

fmt.Println("LinuxButton")

}

func BuildFactory(appearance string) GUIFactory {

switch appearance {

case "Window":

return new(WinFactory)

case "OSX":

return new(OSXFactory)

case "Linux":

return new(LinuxFactory)

}

return nil

}

func main() {

if factory := BuildFactory("Window"); factory != nil {

winButton := factory.CreateButton()

winButton.Paint()

}

if factory := BuildFactory("OSX"); factory != nil {

osxButton := factory.CreateButton()

osxButton.Paint()

}

if factory := BuildFactory("Linux"); factory != nil {

linuxButton := factory.CreateButton()

linuxButton.Paint()

}

}

4. 1. 3. Python 예제

python

from abc import *

class Button:

@abstractmethod

def Paint(self):

pass

class MousePointer:

@abstractmethod

def Paint(self):

pass

class GUIFactory:

@abstractmethod

def CreateButton(self):

return Button

@abstractmethod

def CreateMousePointer(self):

return MousePointer

class WinFactory(GUIFactory):

def CreateButton(self):

return WinButton()

def CreateMousePointer(self):

return WinMousePointer()

class OSXFactory(GUIFactory):

def CreateButton(self):

return OSXButton()

def CreateMousePointer(self):

return OSXMousePointer()

class WinMousePointer(MousePointer):

def Paint(self):

print("윈도우 스타일로 마우스 포인터를 그립니다.")

class OSXMousePointer(MousePointer):

def Paint(self):

print ("OSX 스타일로 마우스 포인터를 그립니다.")

class WinButton(Button):

def Paint(self):

print ("윈도우 스타일로 버튼을 그립니다.")

class OSXButton(Button):

def Paint(self):

print ("Mac OSX 스타일로 버튼을 그립니다.")

class Settings:

@staticmethod

def Default():

return Appearance.WIN

import enum

class Appearance(enum.Enum):

WIN = 0

OSX = 1

def main():

apperance = Settings.Default()

if apperance == Appearance.WIN:

factory = WinFactory()

elif apperance == Appearance.OSX:

factory = OSXFactory()

button = factory.CreateButton()

mousePointer = factory.CreateMousePointer()

button.Paint()

mousePointer.Paint()

if __name__ == '__main__':

main()

```

위 코드는 추상 팩토리 패턴을 파이썬으로 구현한 예제이다.

  • `Button`과 `MousePointer`는 추상 클래스로, 각각 `Paint`라는 추상 메서드를 가진다.
  • `GUIFactory`는 추상 클래스로, `CreateButton`과 `CreateMousePointer`라는 추상 메서드를 가진다. 이 메서드들은 각각 `Button`과 `MousePointer`를 반환한다.
  • `WinFactory`와 `OSXFactory`는 `GUIFactory`를 상속받는 구체 클래스이다. 각 운영체제에 맞는 버튼과 마우스 포인터를 생성한다.
  • `WinMousePointer`, `OSXMousePointer`, `WinButton`, `OSXButton`은 각각 `MousePointer`와 `Button`을 상속받는 구체 클래스이다. `Paint` 메서드를 통해 각 운영체제에 맞는 스타일로 렌더링한다.
  • `Settings` 클래스는 `Default`라는 정적 메서드를 통해 기본 설정을 반환한다.
  • `Appearance`는 `enum`을 사용하여 운영체제 설정을 나타낸다.
  • `main` 함수에서는 `Settings.Default()`를 통해 설정을 가져와 해당 설정에 맞는 팩토리를 생성하고, 팩토리의 `CreateButton`과 `CreateMousePointer` 메서드를 통해 버튼과 마우스 포인터를 생성한다. 마지막으로, 생성된 버튼과 마우스 포인터의 `Paint` 메서드를 호출하여 렌더링한다.


이 예제에서는 윈도우 운영체제 설정을 기본값으로 사용하며, `Settings.Default()`의 반환값을 변경하여 다른 운영체제 설정을 사용할 수 있다.

4. 1. 4. PHP 예제

php

interface Button

{

public function paint();

}

interface GUIFactory

{

public function createButton(): Button;

}

class WinFactory implements GUIFactory

{

public function createButton(): Button

{

return new WinButton();

}

}

class OSXFactory implements GUIFactory

{

public function createButton(): Button

{

return new OSXButton();

}

}

class WinButton implements Button

{

public function paint()

{

echo "Windows Button";

}

}

class OSXButton implements Button

{

public function paint()

{

echo "OSX Button";

}

}

$appearance = "osx";

$factory = NULL;

switch ($appearance) {

case "win":

$factory = new WinFactory();

break;

case "osx":

$factory = new OSXFactory();

break;

default:

break;

}

if ($factory instanceof GUIFactory) {

$button = $factory->createButton();

$button->paint();

}

4. 2. 응용 사례: DOM

문서 객체 모델(DOM)은 추상 팩토리 패턴을 응용한 API 가운데 하나이다.[5]

역할해당 요소
AbstractFactory[http://download.java.net/jdk/jdk-api-localizations/jdk-api-ja/builds/latest/html/ja/api/org/w3c/dom/Document.html org.w3c.dom.Document]
AbstractFactory#createProduct()[http://download.java.net/jdk/jdk-api-localizations/jdk-api-ja/builds/latest/html/ja/api/org/w3c/dom/Document.html#createElement(java.lang.String) org.w3c.dom.Document#createElement(String)], [http://download.java.net/jdk/jdk-api-localizations/jdk-api-ja/builds/latest/html/ja/api/org/w3c/dom/Document.html#createTextNode(java.lang.String) org.w3c.dom.Document#createTextNode(String)] 등
Product[http://download.java.net/jdk/jdk-api-localizations/jdk-api-ja/builds/latest/html/ja/api/org/w3c/dom/Element.html org.w3c.dom.Element], [http://download.java.net/jdk/jdk-api-localizations/jdk-api-ja/builds/latest/html/ja/api/org/w3c/dom/Text.html org.w3c.dom.Text] 등


5. 팩토리 메서드 패턴과의 차이점

팩토리 메서드 패턴은 클래스 상속을 통해 객체 생성을 위임하는 반면, 추상 팩토리 패턴은 객체 구성을 통해 위임한다.[3] 즉, 팩토리 메서드는 "클래스 패턴", 추상 팩토리는 "객체 패턴"으로 분류할 수 있다.

팩토리 메서드 패턴은 부모 클래스인 Creator 클래스가 자식 클래스인 ConcreteCreator 클래스에 객체 생성을 위임하는 관계이다. 반면, 추상 팩토리 패턴은 Client 인스턴스가 ConcreteFactory 인스턴스에 객체 생성을 위임하는 객체 간의 관계이다.

6. 관련 패턴

프로토타입 패턴을 사용하면 프로토타입 객체를 변경하여 생성할 Product를 변경할 수 있다.[8]

ConcreteFactory는 싱글톤 객체일 수도 있다.[8]

참조

[1] 서적 Head First Design Patterns http://shop.oreilly.[...] O'REILLY 2012-09-12
[2] 서적 Head First Design Patterns http://shop.oreilly.[...] O'REILLY 2012-09-12
[3] 웹사이트 The Abstract Factory design pattern - Problem, Solution, and Applicability http://w3sdesign.com[...] 2017-08-11
[4] 웹사이트 Design Patterns: Abstract Factory http://www.informit.[...] informIT 2009-10-23
[5] 웹사이트 Object Design for the Perplexed http://www.codeproje[...] The Code Project 2009-10-23
[6] 웹사이트 Abstract Factory: Implementation http://www.oodesign.[...] OODesign.com 2012-05-16
[7] 웹사이트 The Abstract Factory design pattern - Structure and Collaboration http://w3sdesign.com[...] 2017-08-12
[8] 서적 オブジェクト指向における再利用のためのデザインパターン "[[ソフトバンクパブリッシング]]"
[9] 웹인용 The Abstract Factory design pattern - Structure and Collaboration http://w3sdesign.com[...] 2017-08-12



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com