생성 패턴 - ③ 추상화 팩토리 패턴
객체를 생성하는 일은 다소 번거롭고 많은 주의가 요구됩니다. 만약 생성 절차가 특별한 규칙을 따라야 한다면 객체를 생성하는 일은 더욱 까다로워집니다. 디자인 패턴에서 생성 패턴은 객체 생성의 어려움을 해소하기 위해 등장했습니다. 생성 패턴은 객체를 만드는 복잡한 과정을 추상화한 패턴입니다. 생성 패턴의 종류는 다음과 같습니다.
- Factory Pattern
- Factory Method Pattern
- Abstract Factory Pattern
- Builder Pattern
- Singleton Pattern
- Prototype Pattern
이번 글에서는 세 번째 추상화 팩토리 패턴에 대해서 다뤄보도록 하겠습니다.
Abstract Factory Pattern
앞서 다룬 팩토리 패턴과, 팩토리 메서드 패턴 모두 하나의 팩토리에서 한 가지의 객체만 생성하는 패턴이었습니다. 이번에 다룰 추상화 팩토리 패턴은 더욱 다양 형태의 객체를 생성할 수 있는 패턴입니다. 예시를 통해서 살펴보도록 하겠습니다.
추상화 팩토리 패턴의 활용
추상화 팩토리 패턴은 매트릭스 관계를 가진 오브젝트를 생성할 때 유용하게 활용할 수 있는 패턴입니다. 예를 들어서 UI를 생성하기 위한 팩토리 패턴을 상상해봅시다. UI에는 Button, Check Box, Scroll Bar 등이 있습니다. 그리고 UI의 테마로 Dark Mode, Light Mode가 있을 수 있습니다.
UI들을 코드로 표현하면 다음과 같습니다.
// Button
class Button {
public:
virtual void Click() = 0;
};
class DarkButton : public Button {
public:
void Click() { cout << "Dark button is clicked" << endl; }
};
class LightButton : public Button {
public:
void Click() { cout << "Light button is clicked" << endl; }
};
// Check Box
class CheckBox {
public:
virtual void Click() = 0;
};
class DarkCheckBox : public CheckBox {
public:
void Click() { cout << "Dark check box is clicked" << endl; }
};
class LightCheckBox : public CheckBox {
public:
void Click() { cout << "Light check box is clicked" << endl; }
};
// Scroll Bar
class ScrollBar {
public:
virtual void Scroll() = 0;
};
class DarkScrollBar : public ScrollBar {
public:
void Scroll() { cout << "Dark scroll bar is scrolled" << endl; }
};
class LightScrollBar : public ScrollBar {
public:
void Scroll() { cout << "Light scroll bar is scrolled" << endl; }
};
추상화 팩토리 패턴에서는 위와 같이 다양한 객체들을 효율적으로 생성할 수 있습니다. 먼저, UI객체를 생성하는 기능을 가진 팩토리 인터페이스 클래스를 만듭니다. 그리고 다크 모드 팩토리와 라이트 모드 팩토리는 이 인터페이스 클래스를 상속받아 각각 테마에 맞는 UI생성 기능을 구현할 수 있습니다. 이를 코드로 구현하면 다음과 같습니다.
class UIFactory{
public:
virtual shared_ptr<Button> CreateButton() = 0;
virtual shared_ptr<CheckBox> CreateCheckBox() = 0;
virtual shared_ptr<ScrollBar> CreateScrollBar() = 0;
};
class DarkUiFactory : public UIFactory {
public:
shared_ptr<Button> CreateButton() { return make_shared<DarkButton>(); }
shared_ptr<CheckBox> CreateCheckBox() { return make_shared<DarkCheckBox>(); }
shared_ptr<ScrollBar> CreateScrollBar() { return make_shared<DarkScrollBar>(); }
};
class LightUiFactory : public UIFactory {
public:
shared_ptr<Button> CreateButton() { return make_shared<LightButton>(); }
shared_ptr<CheckBox> CreateCheckBox() { return make_shared<LightCheckBox>(); }
shared_ptr<ScrollBar> CreateScrollBar() { return make_shared<LightScrollBar>(); }
};
이렇게 만들어진 추상화 팩토리를 활용하면 클라이언트는 아래와 같이 DarkUiFactory의 객체로는 Dark UI를 LightUiFactory 객체로는 Light UI를 쉽게 생성할 수 있습니다.
int main()
{
DarkUiFactory dark_factory;
auto dark_button = dark_factory.CreateButton();
auto dark_checkbox = dark_factory.CreateCheckBox();
auto dark_scrollBar = dark_factory.CreateScrollBar();
dark_button->Click();
dark_checkbox->Click();
dark_scrollBar->Scroll();
LightUiFactory Light_factory;
auto Light_button = Light_factory.CreateButton();
auto Light_checkbox = Light_factory.CreateCheckBox();
auto Light_scrollBar = Light_factory.CreateScrollBar();
Light_button->Click();
Light_checkbox->Click();
Light_scrollBar->Scroll();
return 0;
}
정리
추상화 팩토리 패턴에서 가장 핵심은 다양한 테마를 가진 여러종류의 객체를 생성하는 팩토리 패턴이 필요할 때 효과적으로 사용할 수 있다는 점입니다. 다음 글에서는 빌더 패턴에 대해서 다루도록 하겠습니다.
<출처>
유튜브 채널 "코드없는 프로그래밍": https://www.youtube.com/channel/UCHcG02L6TSS-StkSbqVy6Fg
길벗 출판사: 모던 C++ 디자인 패턴(Dmitri Nesteruk 저)