레이블이 디자인인 게시물을 표시합니다. 모든 게시물 표시
레이블이 디자인인 게시물을 표시합니다. 모든 게시물 표시

2009년 10월 2일 금요일

State Patten을 C로 짜려면?

C에서는 상속을 사용하지 못하지만, 그렇다고 State Patten을 구현하지 못하는 것은 아니다. 아래와 같은 구현으로 C에서 State Patten의 장점을 사용할 수 있을 것 같다. C에서는 인터페이스나 상속이 지원되지 않으므로 function table을 사용하여 이벤트 발생시 각 상태별 실행 함수를 지정하도록 하였다. 사실상 이 function table이 구현의 핵심으로, 상태 변경을 발생시키는 이벤트가 추가 할 때마다, 모든 function table의 해당 함수에 대한 함수 포인터 혹은 null function pointer를 추가해야 한다. 바로 이 부분이 상속과 가상 함수를 지원하지 못하는 C에서 State Pattern을 구현할 때 발생하는 불편함이기는 하지만 여전히 State Pattern의 장점을 그대로 누릴 수 있다. 또한 (당연히) 동일 방법을 사용하여 Strategy Pattern 역시 구현 가능하다.

아래 예에서는 구현을 단순화하기 위해서 상태는 ON/OFF두가지 상태만을 가정하였고, 'n' 입력시 ON상태로, 'f' 입력시 OFF상태로 상태 천이를 하도록 하였다.



#include <stdio.h>

/**********************************************************************
*
* 1. Type defination for Power State management
*
**********************************************************************/

typedef enum {ON,OFF} PowerState;

typedef struct
{
  PowerState currPS;
  void (*on_received_fptr)(struct PwrState **ps );
  void (*off_received_fptr)(struct PwrState **ps );
}PwrState;

/**********************************************************************
*
* 2. Function table for each State.
*
**********************************************************************/
//Prefix ON/OFF means current status when these functions are called.
void ON_off_received(PwrState **ps );
void OFF_on_received(PwrState **ps );
void null_func(PwrState **ps);

//C에서는 가상 함수를 사용할 수 없기 때문에, 아래와 같은 각 상태별
//함수 테이블을 별도로 유지해야 한다.

PwrState psON= {ON,   null_func,      ON_off_received};
PwrState psOFF={OFF,  OFF_on_received,  null_func};


void ON_off_received(PwrState **ps)
{
  printf("Currnt State =%d : 0:ON 1:OFF \n",(int)(*ps)->currPS);
  printf("%s is called\n",__func__);

  printf("change curr power state from ON to OFF\n");
  *ps=&psOFF;
}

void OFF_on_received(PwrState **ps)
{
  printf("Currnt State =%d : 0:ON 1:OFF \n",(int)(*ps)->currPS);
  printf("%s is called\n",__func__);

  printf("change curr power state from OFF to ON\n");
  *ps=&psON;
}

void null_func(PwrState **ps){}

int main(void)
{
  char keyin;
  PwrState *ps=&psOFF;

  printf("Current power state is OFF\n");
  printf("type \'n\' to change power state to ON\n");
  printf("type \'f\' to change power state to OFF\n");

  while(1)
  {
    keyin = getchar();

    switch(keyin)
    {
      case 'n':// change state to ON
        ps->on_received_fptr(&ps);
        break;
      case 'f':// change state to OFF
        ps->off_received_fptr(&ps);
        break;
      default:
        break;
    }
  }
}