Facade 패턴

 

디자인 패턴은 문법이 아니며 방법입니다. 하나의 패턴으로 프로그램 전체를 완성시킬 수는 없습니다. 그리고 완벽하게 룰을 지키는 것보다 유연하게 상황에 따라 여러 패턴들을 조금씩 응용해서 사용할 뿐입니다.

 

개인적으로 너무 복잡한 패턴을 굳이 사용할 필요가 없습니다. 오히려 유지보수 혹은 한 프로젝트에 다수의 개발자가 협업할 경우 코드를 이해하지 못하는 경우가 발생할 수 있습니다. 게다가 인수인계시에는 왜 이런 패턴을 구현했는지 잘 설명해줘야 합니다. 그렇지 않으며 좋은 구조로 잘 설계된 프로그램이 타인에 의해 조금씩 붕괴되는 광경을 목격할 수도 있습니다.

 

보통 알고리즘을 구현할 때 복잡한 절차가 있게 마련입니다. 대부분 메모리 할당이라든가, callback 할당, 이벤트 처리 등으로 복잡해지기 쉽습니다. 그런데 이러한 절차들이 main 한 군데에 집중 된다면 코드를 이해하기 어려울 뿐 만 아니라 유지보수도 어렵게 됩니다.

 

Facade 패턴은 다양한 알고리즘 군을 분리해서 그 절차대로 진행해주는 역할을 합니다. 그러면 유지보수를 할때 해당 facade만 보면 되니 코드를 이해하기 한결 쉬워집니다. 또한 main 코드를 건드리지 않고 기능을 개선하거나 추가, 변경 할 수 있게됩니다.

 

상당히 간단한 main 부터 살펴보겠습니다. 여기서는 하나의 알고리즘군(한개의 목표를 수행하는 기능 집단)을 대표해서 facade라는 기능이 추가되었습니다.

/* main.c */
void main(void)
{
	facade_algorithm_t *facade = setup_algorithm();
	facade->init();
	facade->start();
	facade->stop();
}
 

그럼 facade의 헤더를 보겠습니다. 지금까지 포스팅을 보셨다면 헤더가 interface라는 것을 아시리라 생각됩니다.

/* facade.h */
typedef struct
{
	void (*init)(void);
	void (*start)(void);
	void (*stop)(void);
}algorithm_t;

typedef struct
{
	void (*init)(void);
	void (*start)(void);
	void (*stop)(void);
}facade_algorithm_t;

extern facade_algorithm_t *setup_algorithm(void);
 

두가지 structure가 있습니다. algorithm_t 실제 콘크리트 알고리즘을 위한 것이고 facade_algorithm_t는 facade를 위한 것입니다. main에서 setup_algorithm을 호출하면 facade의 facade_algorithm_t의 pointer를 넘겨주게 됩니다.

 

이제 facade 소스를 보겠습니다. 이전과는 다르게 this를 초기화 함수내에서 초기화하지 않고 선언과 동시에 했습니다. 미묘한 차이가 있으나, 나중에 설명하도록 하겠습니다. setup_algorithm을 하면 facade 객체 pointer를 넘겨줍니다.

/* facade.c */
static void init(void);
static void start(void);
static void stop(void);

static facade_algorithm_t this =
{
	init,
	start,
	stop
}

static algorithm_t *algorithm1 = null;
static algorithm_t *algorithm2 = null;

facade_algorithm_t *setup_algorithm(void)
{
	return &this;
}

static void init(void)
{
	algorithm1 = setup_algorithm1();
	algorithm2 = setup_algorithm1();

	algorithm1->init();
	algorithm2->init();
}

static void start(void)
{
	algorithm1->start();
	algorithm2->start();
}

static void stop(void)
{
	algorithm1->stop();
	algorithm2->stop();
}
 

이전 main에서는 위 코드의 init, start, stop을 호출하게 되는데 실제로는 algorithm1, algorith2 알고리즘 군의 함수를 수행하는게 됩니다. 위의 예제는 init이 상당히 단순한데 실제로는 다양한 절차들이 들어갈 수 있습니다. 여기를 수정하시거나 algorithm1, algorith2 의 실제 구현 코드에서 절차들을 수정하면 됩니다. 그럼 main은 수정을 안해도 되겠지요.

 

그럼 이제 algorithm1 코드를 보도록 하겠습니다. 먼저 헤더입니다. . 아래 코드를 설명하자면 setup_algorithm1 호출해 algorithm_t의 포인터를 넘겨주는 함수입니다. 즉 실제 알고리즘의 포인트를 얻어와 사용하겠다는 의미입니다.

/* facade_algorithm1.h */
extern algorithm_t *setup_algorithm1(void);
 

그럼 algorithm1 을 실제 구현 해 보도록 하겠습니다. 실제 구현할 사항이 있으면 아래 코드를 채워 넣으면 됩니다.

/* facade_algorithm1.c */
static void init(void);
static void start(void);
static void stop(void);

static algorithm_t this =
{
	init,
	start,
	stop
}

algorithm_t *setup_algorithm1(void)
{
	return &this;
}

static void init(void)
{
	// need to implment..
}

static void start(void)
{
	// need to implment..
}

static void stop(void)
{
	// need to implment..
}
 

algorithm2의 코드도 동일합니다. 실제 구현부만 달라지면 됩니다.

/* facade_algorithm2.c */
static void init(void);
static void start(void);
static void stop(void);

static algorithm_t this =
{
	init,
	start,
	stop
}

algorithm_t *setup_algorithm2(void)
{
	return &this;
}

static void init(void)
{
	// need to implment..
}

static void start(void)
{
	// need to implment..
}

static void stop(void)
{
	// need to implment..
}
 

Facade 패턴은 C언어에서 정말 필요한 패턴입니다. C언어는 메모리에 한해서 동적이지 못하고 절차를 중요하게 생각하기 때문에 코드가 많아지는게 필연적입니다.

 

그래서 main에는 코드가 많아지기 쉽습니다. C 프로그램에서는 객체지향 언어의 프로그래밍보다 더 구조적으로 작성해야 생산성 및 유지보수 확장성이 용이해 집니다.

 

오늘은 여기까지 입니다.

'▶ C Application > 디자인 패턴' 카테고리의 다른 글

C언어에서 static 반드시 써야 하는 이유  (0) 2024.02.24
Builder 패턴 - 키(Key)처리  (1) 2024.01.17
Adapter 패턴 - 3  (0) 2023.12.24
Adapter 패턴 - 2  (0) 2023.12.24
Adapter 패턴 - 1  (0) 2023.12.24