C 언어 Design Pattern - Observer Pattern

유명현·2022년 4월 4일

Observer 패턴은 많이 사용하는 코딩 패턴입니다.

Observer 패턴의 사용법은 간단합니다. 메인 프로세스는 observer를 만들어 사용하려는 라이브러리나 API에 등록합니다. 그러면 적당한 이벤트가 발생할 때마다 자신에 등록된 Observer에 메시지나 데이터를 전달해주면 됩니다. 결과적으로 메인 프로세서는 자기 할일을 하다가 observer에 뭔가 전달될 떄마다 처리해 주면됩니다.

습도 측정하는 센서에서 주기적으로 습도를 측정하여 사용자(main 함수)에게 알려주는 처리를 observer 패턴을 이용해 만들어 보겠습니다.

//humidity.h 
#ifndef OBSERVER_HUMIDITY_H_
#define OBSERVER_HUMIDITY_H_

typedef void (*observer_hanlder_t)(uint32_t humi);
bool register_observer(observer_handler_t observer);
bool unregister_observer(observer_hanlder_t observer);
void calculation_humidity(void);
#endif 

//humidity.c 
#define MAX_OBSERVER_COUNT 20
static oberver_handler_t observer_handler[MAX_OBSERVER_COUNT];
static uint8_t observer_handler_len = 0;

bool register_observer(observer_handler_t observer)
{
	if(observer_handler_len >= MAX_OBSERVER_COUNT)
    {
    	return FALSE;
    }
    for(uint8_t observer_cnt = 0; observer_cnt < MAX_OVSERVER_COUNT, observer_cnt++)
    {
    	if(observer_handler[observer_cnt] == observer)
        {
        	return FALSE;
        }
    }
    observer_hanlder[observer_handler_len++] = observer;
    return TRUE;
}

bool unregister_observer(observer_hanlder_t observer)
{
	for(uint8_t observer_cnt = 0; observer_cnt < observer_handler_len; observer_cnt++)
    {
    	if(observer_handler[observer_cnt] == observer)
        {
        	for(uint8_t cnt_temp = observer_cnt; cnt_temp < observer_handler_len; cnt_temp++)
            {
            	if((cnt_temp - 1) == observer_len)
                {
                	break;
                }
                observer_hanlder[cnt_temp] = observer_handler[cnt_temp -1];
            }
            observer_hanlder_len--;
            return TRUE;
        }
    }
    return FALSE;
}

static void update_observer(uint32_t humi)
{
	for(uint8_t observer_cnt = 0; observer_cnt < observer_handler_len; observer_cnt++)
    {
    	observer_handler[observer_cnt](humi);
    }
}

void calculate_humidity(void)
{
	uint32_t humi = 0;
    //습도 계산 
    update_observer (humi);
}

위에 코드를 살펴보겠습니다.
먼저 MAX_OBSERVER_COUNT는 20으로 observer등록이 최대 20개까지 될 수 있게 함수포인터 배열로 만들었습니다.

register_observer 함수를 통해서 observer들을 등록하게 되어 있고, 만약 observer들 중에 등록되어 있다면, FALSE를 반환하게 만들었습니다.

unregister_observer함수를 통해서 등록된 observer들을 헤체할 수 있습니다. 자료구조 observer_hanlder배열에서 해당되는 observer가 있다면 삭제하고 뒤에 있는 배열을 앞으로 당겨오는 구조입니다.

calculate_humidity함수를 통해 습도를 계산하고 update_observer를 통하여 받은 습도값을 등록된 observer들에게 알려줍니다.
(보통 calculate_humidity함수를 습도센서 adc 인터텁르 또는 timer를 통하여 사용자가 원하는 방법으로 함수를 호출하여 계산합니다.)

이제 main함수에서 보면

static void display_humidity_hanlder(uint32_t humidity);
static void file_write_humidty_handler(uint32_t humidity);

void main(void)
{
	register_observer(display_humidty_handler);
    register_observer(file_write_humidity_handler);
    
    while(1)
    {
    	calculate_humidty();
        delay_ms(1000);
    }
}
static void display_humidity_hanlder(uint32_t humidity)
{
	//TODO : 습도 화면 표시 작성
}
static void file_write_humidty_handler(uint32_t humidity)
{
	//TODO : 습도 파일 저장 작성 
}

main함수에서 observer 등록 2개를 합니다. 그다음 while문을 통해 습도 센서값을 계산한 후 등록된 observer들에게 결과를 알려주게 됩니다. 결과를 받은 observer들은 각자의 역할대로 맡은 업무를 처리하게 됩니다.

profile
기억보다 기록을

0개의 댓글