추상팩토리 패턴 (Abstract Factory Pattern) [첫번째]

1. 객체 생성을 위한 디자인 패턴

  • Singleton(싱글톤) 패턴
  • Abstract Factory 패턴
  • Builder 패턴
  • Factory Method 패턴
  • Prototype 패턴

이제 이번 시간부터는 객체 생성을 위한 디자인 패턴 중에서 Abstract Factory 패턴에 대해 알아보겠습니다. 일단 개념부터 알아보도록 하죠.

Abstract Factory 패턴은 객체를 생성할 때 반드시 필요한 제품군에 해당하는 것만 생성해서 사용하고자 할 경우 사용합니다.
제품군의 대표적인 예는 자동자를 생각하면 될 것 같습니다.
자동차는 흔히 종합 예술이라고도 하잖아요 ? 모든 기술이 축적된 제품이기 때문이죠.
즉, 자동차 내부에는 엔진이라는 제품, 오디오라는 제품, 네비게이터라는 제품 등 여러 제품이 있습니다.
하지만, 이러한 각 제품들은 아마도 소나타에 들어가는 제품과 그랜저에 들어가는 제품, 프라이드에 들어가는 제품이 제각기 다를 것입니다.
소나타에 들어가는 것들은 그러한 제품들끼리, 그리고 프라이드에 들어가는 제품들끼리 묶어놓은 것을 제품군이라고 합니다.
즉, 같은 환경 내에서 동작하게 될 것들끼리만 묶어놓은 것을 말합니다.

소프트웨어에서도 이 같은 제품군을 생각해볼 수 있습니다.
예를 들면, 다양한 플랫폼에서 동작해야 하는 프로그램을 만들어야 한다고 가정해 봅시다.
이 프로그램은 기능 단위로 쪼갠 다양한 Class 를 가지고 있는데, 이 Class 는 아마도 운영체제에 따라 달라져야할 것입니다.
왜냐하면, 운영체제에 따라 Class 내부의 함수 구현 등도 달라질 것이기 때문이다.

제가 전문인 분야가 DB (Database)이니 DB 를 만든다고 가정하고 접근해 봅시다.
DB 에는 다음 3 가지 정도의 모듈은 반드시 필요합니다.

  1. 사용자와의 접속을 제어하는 Session Control Module
  2. 사용자의 Query 를 분석하고 최적화시키는 Query Optimizer
  3. Disk 또는 Memory 에 저장된 데이터에 접근 및 저장을 수행하는 Storage Manager

사용자가 Database 에 접속해서 Query 를 통해 저장된 데이터를 조회해보기까지 DB 엔진에서는 위의 모듈들이 유기적으로 잘 동작하여 결과를 던져주도록 구현되어 있습니다.
그런데, DB 는 다양한 플랫폼을 지원해야하는 경우가 많습니다.
SunOS, HP, IBM AIX, Linux 등 다양한 환경을 모두 지원해야 Hardware 및 운영체제 플랫폼에 구애받지 않고 좀 더 다양한 고객을 확보할 수 있기 때문입니다.
위와 같이 DB 를 예를 든다면 3 가지의 모듈이 곧 제품군이 될 것입니다.
위 3 가지의 모듈이 플랫폼에 따라 달라지게 되겠죠.

우리는 개발 인력이 부족해서 Linux 와 AIX 만 지원하는 DB 를 만든다고 가정해 봅시다.
이 때 필요한 모듈을 생각해보면...

  • Session Control Module for Linux
  • Query Optimizer for Linux
  • Storage Manager for Linux
  • Session Control Module for AIX
  • Query Optimizer for AIX
  • Storage Manager for AIX

위와 같이 6 개의 모듈이 필요할 것입니다.
각각을 Class 로 구현한다고 생각하면 총 6 개의 Class 가 필요하겠죠.
하지만, 특정 고객에게 제품을 공급하고자 하는데 그 고객은 Linux 만 사용하는 고객이라고 가정해보면, 그 고객에게 제공할 제품에 AIX 용 Class 들이 필요할까요 ?
아마도 불필요할 것입니다.
이럴 때는 Linux 용 모듈들만 즉, Linux 용 Class 의 객체들만 생성해서 동작하도록 하면 됩니다.
Linux 에서 동작하는데 AIX 용 객체들까지 생성할 필요는 없잖아요 ?
(설사 생성한다 해도 동작도 제대로 못할 것이기 때문에 생성을 막는 것이 정답이겠죠.)

자, 그럼 우리는 개발자이기 코드로 얘기해 봅시다. ^^
개념적으로 pseudo code 만 작성해 보도록 하죠.

class linux_session_control {};
class linux_query_proc {};
class linux_storage_mgr {};
class aix_session_control {};
class aix_query_proc {};
class aix_storage_mgr {};

int platform;

void make_session_control()
{
    // platform 별로 각각 적합한 객체 생성
    if( platform_is_linux )
    {
        linux_session_control  session_control;
    }
    else if( platform_is_aix )
    {
        aix_session_control session_control;
    }
    else
    {
        // invalid platform
    }
}

void make_query_proc()
{
    // platform 별로 각각 적합한 객체 생성
    if( platform_is_linux )
    {
        linux_query_proc query_proc;
    }
    else if( platform_is_aix )
    {
        aix_query_proc query_proc;
    }
    else
    {
        // invalid platform
    }
}

void make_storage_mgr()
{
    // 위와 같은 로직
}

int main()
{
    // check plaform here
    // platform 만 결정해주면 하위 함수에서 알아서 알맞은 객체를 생성해 줌.
    make_session_control();
    make_query_proc();
    make_storage_mgr();
}

위의 코드를 대강 보면 마치 platform 에 따라 각기 알맞은 객체를 알아서 생성해주고 사용자는 platform 만 결정해주면 되는 좋은 코드처럼 보입니다.
하지만, DB 의 부품이 Session Control, Query Optimizer, Storage Manager 외에 아주 다양하고, 지원해야할 platform 은 날이 갈수록 늘어난다고 가정을 해보죠.
이러한 기능 확장과 환경의 확장은 위의 코드를 구석구석 돌아다니며 모두 else if 를 추가해주어야 한다는 것을 의미합니다.
간단한 소프트웨어라면 상관없지만, 백만 라인이 넘어가고 위와 같은 로직이 여기 저기 산재해 있다면, 아마도 현재 이외의 platform 지원은 거의 포기해야할 지경일 겁니다.

그렇다면 위의 단점을 개선할 방법이 없을까요 ?
물론 있습니다. ^^
위 코드의 문제에 대한 해결방법은 다음 시간에 살펴볼 것인데요. 다음의 2 가지 방식을 살펴볼 것입니다.

  • 객체 생성 전담 클래스를 이용하는 방법
  • Abstract Factory 패턴을 이용하는 방법

 

You may also like...

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x