Menu
Coddy logo textTech

인터페이스 구현하기

Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 41번째.

이제 인터페이스가 무엇인지 — 함수 포인터만을 포함하는 구조체 — 이해했으므로, 그 계약을 충족하는 구체적인 구현체(concrete implementations)를 만들 차례입니다.

이전 레슨에서 다루었던 ILogger 인터페이스를 다시 떠올려 봅시다:

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

이 인터페이스를 구현하기 위해 LogFunc 시그니처와 일치하는 실제 함수를 작성한 다음, 해당 함수들이 할당된 ILogger 인스턴스를 생성합니다:

void console_log(const char* message) {
    printf("[CONSOLE] %s\n", message);
}

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // 파일 출력 시뮬레이션
}

ILogger create_console_logger() {
    ILogger logger = { console_log };
    return logger;
}

ILogger create_file_logger() {
    ILogger logger = { file_log };
    return logger;
}

각 "생성자(constructor)" 함수는 서로 다른 함수가 연결된 ILogger를 반환합니다. 이 로거들을 사용하는 코드는 어떤 구현체를 전달받았는지 알 필요가 없습니다:

void do_work(ILogger* logger) {
    logger->log("Starting work...");
    logger->log("Work complete!");
}

int main() {
    ILogger console = create_console_logger();
    ILogger file = create_file_logger();
    
    do_work(&console);  // console_log 사용
    do_work(&file);     // file_log 사용
    return 0;
}

do_work 함수는 로깅 구현과 완전히 분리되어 있습니다. 핵심 로직을 변경하지 않고도 로거를 자유롭게 교체할 수 있습니다. 이것이 바로 인터페이스를 기반으로 프로그래밍하는 것의 힘입니다.

challenge icon

챌린지

쉬움

서로 다른 구현이 동일한 인터페이스 계약을 어떻게 충족할 수 있는지 보여주는 INotifier 시스템을 구축해 보겠습니다. 공통 인터페이스를 따르지만 서로 다른 출력을 생성하는 구체적인 알림 도구인 EmailNotifierSMSNotifier를 만들 것입니다.

코드는 세 개의 파일로 구성됩니다:

  • notifier.h: 여기에 인터페이스를 정의합니다. const char* 메시지를 매개변수로 받고 아무것도 반환하지 않는 NotifyFunc라는 함수 포인터 타입을 생성하세요. 그런 다음 이 타입의 notify 함수 포인터만 포함하는 INotifier 구조체를 정의합니다. 또한 INotifier를 값으로 반환하는 두 개의 생성자 함수 create_email_notifiercreate_sms_notifier를 선언하세요.
  • notifier.c: 여기에 구체적인 알림 함수와 생성자를 구현합니다. 다음을 생성하세요:
    • email_notify — 메시지를 [EMAIL] message 형식으로 출력합니다.
    • sms_notify — 메시지를 [SMS] message 형식으로 출력합니다.
    • create_email_notifieremail_notify와 연결된 INotifier를 반환합니다.
    • create_sms_notifiersms_notify와 연결된 INotifier를 반환합니다.
  • main.c: 여기서 모든 것을 하나로 합칩니다. 알림 유형과 메시지를 읽고, 생성자 함수를 사용하여 적절한 알림 도구를 생성한 다음, 인터페이스를 통해 알림을 보냅니다.

프로그램은 두 개의 입력을 받습니다: 알림 유형 (이메일은 1, SMS는 2)과 보낼 메시지입니다.

생성자 함수를 사용하여 적절한 알림 도구를 생성한 다음, 인터페이스를 통해 notify를 호출하여 메시지를 표시하세요.

유형이 1이고 메시지가 Meeting at 3pm일 때의 예시 출력:

[EMAIL] Meeting at 3pm

유형이 2이고 메시지가 Your code shipped일 때의 예시 출력:

[SMS] Your code shipped

이 패턴의 장점은 main.c가 각 알림 도구가 내부적으로 어떻게 작동하는지 알 필요가 없다는 것입니다. 단순히 인터페이스의 notify 함수를 호출하면 올바른 구현이 실행됩니다. 헤더 파일에 인클루드 가드(include guards)를 사용하는 것을 잊지 마세요.

치트 시트

C 언어에서 인터페이스를 구현하려면 함수 포인터 시그니처와 일치하는 구체적인 함수를 생성한 다음, 이를 인터페이스 인스턴스에 할당합니다.

함수 포인터를 사용하여 인터페이스를 정의합니다:

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

구체적인 구현을 생성합니다:

void console_log(const char* message) {
    printf("[CONSOLE] %s\n", message);
}

void file_log(const char* message) {
    printf("[FILE] %s\n", message);
}

생성자 함수를 사용하여 인터페이스 인스턴스를 생성합니다:

ILogger create_console_logger() {
    ILogger logger = { console_log };
    return logger;
}

ILogger create_file_logger() {
    ILogger logger = { file_log };
    return logger;
}

인터페이스를 사용하는 코드는 구체적인 구현으로부터 분리(decoupled)됩니다:

void do_work(ILogger* logger) {
    logger->log("Starting work...");
}

int main() {
    ILogger console = create_console_logger();
    ILogger file = create_file_logger();
    
    do_work(&console);  // Uses console_log
    do_work(&file);     // Uses file_log
    return 0;
}

직접 해보기

#include <stdio.h>
#include "notifier.h"

int main() {
    int type;
    char message[256];
    
    // 알림 유형 읽기 (이메일은 1, SMS는 2)
    scanf("%d", &type);
    getchar(); // 개행 문자 소비
    
    // 메시지 읽기
    fgets(message, sizeof(message), stdin);
    // 끝에 개행 문자가 있으면 제거
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: 유형에 따라 적절한 notifier 생성
    // 유형 1에 대해 create_email_notifier() 사용
    // 유형 2에 대해 create_sms_notifier() 사용
    
    // TODO: 인터페이스를 통해 notify 함수 호출
    // notifier.notify(message);
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨