프로그래밍 기술/Escort GoF의 디자인 패턴

1. 추상 팩토리 패턴 (Abstract Factory Pattern) [Escort GoF의 디자인 패턴]

언제나휴일 2016. 4. 4. 13:17
반응형

1. 추상 팩토리 패턴 (Abstract Factory Pattern)

 

1.1 개요

 

 프로그래밍하다 보면 특정 목적에 따라 사용해야 하는 개체들이 서로 호환성이 있어야 하는 경우가 발생합니다. 목적에 따라 사용해야 하는 개체군이 다른 경우에 특정 목적에 맞게 호환성 있는 개체가 무엇인지를 조사하고 주의 깊게 사용하는 비용이 발생합니다. 이럴 때 추상 팩토리 패턴을 사용하면 효과적으로 비용을 줄일 수 있습니다. 특히, 특정 작업을 구현할 때 호환성이 있는 여러 개체를 사용해야 한다면 추상 팩토리 패턴을 사용하세요. 추상 팩토리 패턴을 사용하면 표준화된 방식에 의해 자신에게 맞는 개체군을 효과적으로 이용할 수 있게 해 줍니다.

 

 추상 팩토리 패턴에서는 서로 호환성 있는 개체들을 생성하는 부분만 담당하는 개체를 제공하는 것입니다. 이와 같은 개체를 팩토리 개체라 부릅니다. 하나의 팩토리 개체를 통해 생성되는 개체들은 상호 호환성을 보장받기 때문에 사용자는 호환성 있는 개체가 무엇인지에 대한 고민할 필요가 없게 됩니다. 그리고 여러 팩토리 개체 형식에 대한 표준화된 인터페이스를 제공합니다. 이를 통해 사용자는 자신이 사용해야 할 목적과 환경에 맞는 팩토리 개체가 무엇인지에 대해서만 판단을 하면 됩니다. 이미 팩토리 개체를 통해 생성되는 개체는 이미 추상화된 표준 인터페이스를 사용하기 때문에 서로 다른 목적이나 환경에서 사용되는 경우에도 사용 방법은 같아질 것입니다. 결국, 사용자는 사용 목적이나 환경이 바뀌어 다른 개체군을 선택해야 할 때에도 단순히 팩토리 개체만 교체하면 되기 때문에 유지보수 비용이 줄어들게 됩니다.

 

1. 2 시나리오

 

 EHWorld에는 Everyday 카메라와 Holiday 카메라가 있습니다. 두 종류의 카메라 모두 렌즈 교환식 카메라입니다. 저는 사람이나 건물 등을 촬영할 때에는 부드럽게 표현해 주는 Everyday 카메라를 선호합니다. 그리고 여행에서 아름다운 풍경을 찍을 때에는 자연스럽게 표현해 주는 Holiday 카메라를 선호합니다. 그런데 저에게는 고민이 하나 있습니다. 사진에 취미를 갖고 렌즈를 하나하나 구매하다 보니 여행을 갈 때마다 Holiday 카메라와 호환되는 렌즈를 찾는데 너무 많은 시간이 듭니다. 물론, Everyday 카메라와 호환되는 렌즈를 찾을 때도 너무 많은 시간이 소요되네요.

 

 어떻게 하면 제 고민을 해결할 수 있을까요?

 

 어느 날 저의 아내가 저에게 선물을 가지고 왔습니다. 두 개의 라면 박스였습니다. 저는 순간 짜증이 밀려왔지만, 아내의 말을 듣고 나니 짜증은 고마움과 기쁨으로 전이되었습니다.

 

 "E 라면 박스에는 Everyday 렌즈들을 넣고 H 라면 박스에는 Holiday 렌즈들을 넣으면 좋지 않을까?"

 

 예전보다 렌즈를 찾는데 드는 비용은 줄어들었습니다. 하지만 여전히 많은 시간을 소요해야 원하는 렌즈를 찾을 수 있었습니다. 봄에 꽃을 찍을 때에는 10 mm 단 렌즈를 사용하면 한 송이를 클로즈업 할 수 있어 봄의 기운을 전달할 수 있습니다. 강 건너 풍경을 찍을 때는 줌 렌즈를 사용해야 원하는 피사체를 효과적으로 표현할 수 있고요. 사랑하는 아들을 찍을 때에는 35 mm 단 렌즈를 선호하고 영원한 동반자인 사랑하는 나의 아내를 찍을 때에는 45 mm 단 렌즈를 선호합니다. 그리고 제가 강의했던 학생들이 교육 과정을 마치고 나면 수료식을 수행합니다. 이때는 70 mm 단 렌즈를 사용하곤 합니다. 가끔 아들이나 아내가 저의 카메라와 렌즈를 사용할 일이 있게 되면 어떠한 렌즈를 사용하는 것이 좋은지를 몰라서 대충 골라 가곤 합니다. 그리고는 촬영된 사진이 이상하다고 투덜대곤 합니다.

 

 어떻게 하면 우리 가족의 고민을 해결할 수 있을까요?

 

 이 문제를 해결하기 위해 라면 박스 안에 칸막이를 만들었습니다. 3 X 3 형태로 만들어 우측부터 단 렌즈, 표준 렌즈, 줌 렌즈를 배치했습니다. 그리고 앞에는 가까운 피사체를 찍을 수 있는 렌즈를 배치하고 맨 뒤에는 먼 곳에 있는 피사체를 찍을 수 있는 렌즈를 배치하였습니다. 그리고 박스 앞에 종류별로 카메라를 배치할 수 있는 공간을 별도로 만들었습니다.

 

 그 후로 우리 가족은 렌즈를 찾는 비용을 줄일 수 있게 되었고 아내와 아들도 자신들이 찍은 사진에 만족해합니다. 그런데 이제 아내와 아들이 저와 같이 여행을 가면 서로 자신이 사진을 찍어야 한다고 승강이를 벌이는 행복한 고민에 빠졌습니다.

 





AboutAbstractFactory.zip


//common.h

#pragma once

 

#include <iostream>

using std::cout;

using std::endl;

#include <vector>

using std::vector;

 

//Lens.h

#pragma once

 

class Lens

{

public:   

             virtual void Take()=0;

};

 

//EvLens.h

#pragma once

#include "Lens.h"

 

class EvLens :

             public Lens

{           

public:   

             virtual void Take();

             void AutoFocus();

};

 

//EvLens.cpp

#include "EvLens.h"

#include "common.h"

 

void EvLens::Take()

{

             cout<<"부드럽다."<<endl;   

}

void EvLens::AutoFocus()

{

             cout<<"AutoFocus......"<<endl;

}

 

//HoLens.h

#pragma once

#include "Lens.h"

 

class HoLens :

             public Lens

{

public:

             virtual void Take();

             void ManualFocus();

};

 

//HoLens.cpp

#include "HoLens.h"

#include "common.h"

 

void HoLens::Take()

{

             cout<<"자연스럽다."<<endl;

}

void HoLens::ManualFocus()

{

             cout<<"사용자의 명령대로 초점을 잡다. "<<endl;

}

 

//Camera.h

#pragma once

 

#include "Lens.h"

class Camera

{

             Lens *lens;

public:                 

             virtual bool TakeAPicture();

             virtual bool PutInLens(Lens *lens) = 0;

             Lens *GetOutLens();

protected:

             Camera(void);                                 

             void SetLens(Lens *_lens);    

             Lens *GetLens();

};

 

//Camera.cpp

#include "Camera.h"

 

Camera::Camera(void)

{

             lens = 0;

}

bool Camera::TakeAPicture()

{

             if(lens == 0)

             {

                           return false;

             }

             lens->Take();

             return true;

}

Lens *Camera::GetOutLens()

{

             Lens *re = lens;

             lens = 0;

             return re;

}

void Camera::SetLens(Lens *_lens)

{

             lens = _lens;

}

Lens *Camera::GetLens()

{

             return lens;

}

 

//EvCamera.h

#pragma once

#include "Camera.h"

#include "EvLens.h"

 

class EvCamera :

             public Camera

{           

public:   

             virtual bool TakeAPicture();

             virtual bool PutInLens(Lens *lens);

};

 

//EvCamera.cpp

#include "EvCamera.h"

 

bool EvCamera::PutInLens(Lens *lens)

{

             EvLens *evlens = dynamic_cast<EvLens *>(lens);

             if(evlens == 0)

             {

                           return false;

             }

 

             Camera::SetLens(lens);

             return true;

}

 

bool EvCamera::TakeAPicture()

{

             Lens *lens = Camera::GetLens();

             EvLens *evlens = dynamic_cast<EvLens *>(lens);

             if(evlens == 0)

             {

                           return false;

             }

 

             evlens->AutoFocus();

             return Camera::TakeAPicture();

}

 

//HoCamera.h

#pragma once

#include "Camera.h"

#include "HoLens.h"

 

class HoCamera :

             public Camera

{

public:

             virtual bool TakeAPicture();

             virtual bool PutInLens(Lens *lens);

};

 

//HoCamera.cpp

#include "HoCamera.h"

 

bool HoCamera::PutInLens(Lens *lens)

{

             HoLens *holens = dynamic_cast<HoLens *>(lens);

             if(holens == 0)

             {

                           return false;

             }

 

             Camera::SetLens(lens);

             return true;

}

 

bool HoCamera::TakeAPicture()

{

             Lens *lens = Camera::GetLens();

             HoLens *holens = dynamic_cast<HoLens *>(lens);

             if(holens == 0)

             {

                           return false;

             }

 

             holens->ManualFocus();

             return Camera::TakeAPicture();

}

 

//DayFactory.h

#pragma once

 

#include "Camera.h"

#include "Lens.h"

#include "common.h"

 

typedef vector<Camera *> Cameras;

typedef vector<Lens *> Lenses;

 

typedef vector<Camera *>::iterator CIter;

typedef vector<Lens *>::iterator LIter;

 

class DayFactory

{           

             Cameras cameras;

             Lenses  lenses;

public:

             virtual Camera *CreateCamera()=0;

             virtual Lens *CreateLens()=0;

             ~DayFactory();

protected:

             void PutCamera(Camera *camera);

             void PutLens(Lens *lens);

private:

             void DisposeCameras();

             void DisposeLens();

};

 

//DayFactory.cpp

#include "DayFactory.h"

 

 

void DayFactory::PutCamera(Camera *camera)

{

             cameras.push_back(camera);

}

void DayFactory::PutLens(Lens *lens)

{

             lenses.push_back(lens);

}

 

DayFactory::~DayFactory()

{

             DisposeCameras();

             DisposeLens();

}

void DayFactory::DisposeCameras()

{

             CIter iter = cameras.begin();

             CIter end = cameras.end();

 

             Camera *camera=0;

             for(   ; iter != end; ++iter)

             {

                           camera = *iter;

                           delete camera;

             }

}

void DayFactory::DisposeLens()

{

             LIter iter = lenses.begin();

             LIter end = lenses.end();

 

             Lens *lens=0;

             for(   ; iter != end; ++iter)

             {

                           lens = *iter;

                           delete lens;

             }

}

 

//EvDayFactory.h

#pragma once

#include "DayFactory.h"

#include "EvCamera.h"

#include "EvLens.h"

class EvDayFactory :

             public DayFactory

{

public:

             virtual Camera *CreateCamera();

             virtual Lens *CreateLens();

};

 

//EvDayFactory.cpp

#include "EvDayFactory.h"

 

Camera *EvDayFactory::CreateCamera()

{

             return new EvCamera();

}

Lens *EvDayFactory::CreateLens()

{

             return new EvLens();

}

 

//HoDayFactory.h

#pragma once

#include "DayFactory.h"

#include "HoCamera.h"

#include "HoLens.h"

class HoDayFactory :

             public DayFactory

{

public:

             virtual Camera *CreateCamera();

             virtual Lens *CreateLens();

};

 

//HoDayFactory.cpp

#include "HoDayFactory.h"

 

Camera *HoDayFactory::CreateCamera()

{

             return new HoCamera();

}

Lens *HoDayFactory::CreateLens()

{

             return new HoLens();

}

 

//Tester.h

#pragma once

#include "EvDayFactory.h"

#include "HoDayFactory.h"

class Tester

{

             DayFactory *factories[2];      

public:

             Tester(void);

             ~Tester(void);

             void Test();

private:

             void Initialize();     

             void TestCase(Camera *camera,Lens *lens);

             void TestDirect();

             void TestUsingFactory();

};

 

//Tester.cpp

#include "Tester.h"

#include "common.h"

 

Tester::Tester(void)

{

             Initialize();

}

 

Tester::~Tester(void)

{

             delete factories[0];

             delete factories[1]; 

}

 

void Tester::Initialize()

{

             factories[0] = new EvDayFactory();

             factories[1] = new HoDayFactory();     

}

 

 

void Tester::Test()

{

             TestDirect();

             TestUsingFactory();

}

 

void Tester::TestDirect()

{

             Camera *camera = new EvCamera();

             Lens *lens = new HoLens();

             TestCase(camera,lens);

             delete camera;

             delete lens;

}

void Tester::TestUsingFactory()

{           

             Camera *camera = factories[0]->CreateCamera();

             Lens *lens = factories[0]->CreateLens();

             TestCase(camera,lens);

 

             camera = factories[1]->CreateCamera();

             lens = factories[1]->CreateLens();

             TestCase(camera,lens);

}

void Tester::TestCase(Camera *camera,Lens *lens)

{           

             cout<<"테스트"<<endl;

             if(camera->PutInLens(lens)==0)

             {

                           cout<<"카메라에 렌즈가 장착이 되지 않았음"<<endl;

             }

             if(camera->TakeAPicture() ==0)

             {

                           cout<<"사진이 찍히지 않았습니다."<<endl;

             }

}

 

//Demo.cpp

#include "Tester.h"

 

int main()

{

             Tester *tester = new Tester();

             tester->Test();

             delete tester;

             return 0;

}

 


IT 전문가로 가는 길 Escort GoF의 디자인 패턴
국내도서
저자 : 장문석
출판 : 언제나휴일 2013.04.01
상세보기


 

반응형