인터페이스 구현하기
Coddy C 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 41번째.
이제 interface가 무엇인지, 즉 함수 포인터만 포함하는 구조체라는 것을 이해했으니, 이제 그 계약을 충족하는 구체적인 구현을 만들어 보겠습니다.
이전 강의에서 살펴본 ILogger 인터페이스를 떠올려 보세요:
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;이 interface를 구현하려면 LogFunc 시그니처와 일치하는 실제 functions를 작성한 다음, 해당 functions를 할당하여 ILogger 인스턴스를 create합니다:
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" function은 서로 다른 function이 연결된 ILogger를 반환합니다. 이러한 logger를 사용하는 코드는 어떤 구현을 받았는지 알 필요가 없습니다.
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 function은 로깅 구현과 완전히 분리되어 있습니다. 핵심 로직을 변경하지 않고도 logger를 자유롭게 교체할 수 있습니다. 이것이 interface를 대상으로 프로그래밍하는 것의 힘입니다.
챌린지
쉬움INotifier 시스템을 만들어 서로 다른 구현이 동일한 interface contract를 어떻게 충족할 수 있는지 살펴보겠습니다. 공통 interface를 따르지만 서로 다른 output을 생성하는 구체적인 notifier인 EmailNotifier와 SMSNotifier를 만들게 됩니다.
코드는 세 개의 파일로 구성합니다.
notifier.h: 여기에서 interface를 Define합니다.const char*message를 받고 아무것도 반환하지 않는NotifyFunc라는 function pointer type을 Create합니다. 그런 다음 이 type의notifyfunction pointer만 포함하는INotifierstruct를 Define합니다. 또한 각각 값으로INotifier를 반환하는 두 constructor functions인create_email_notifier와create_sms_notifier도 Declare합니다.notifier.c: 여기에서 구체적인 notification functions와 constructors를 Implement합니다. 다음을 Create합니다.email_notify: 다음 형식으로 message를 출력합니다:[EMAIL] messagesms_notify: 다음 형식으로 message를 출력합니다:[SMS] messagecreate_email_notifier:email_notify에 연결된INotifier를 반환합니다.create_sms_notifier:sms_notify에 연결된INotifier를 반환합니다.
main.c: 여기에서 모든 것을 하나로 결합합니다. notification type과 message를 읽고, constructor functions를 사용해 appropriate notifier를 Create한 다음, interface를 통해 notification을 보냅니다.
프로그램은 두 가지 입력을 받습니다. notification type(email은 1, SMS는 2)과 전송할 message입니다.
constructor functions를 사용해 appropriate notifier를 Create한 다음, interface를 통해 notify를 Call하여 message를 표시합니다.
type이 1이고 message가 Meeting at 3pm일 때의 output 예시입니다.
[EMAIL] Meeting at 3pmtype이 2이고 message가 Your code shipped일 때의 output 예시입니다.
[SMS] Your code shipped이 패턴의 장점은 main.c가 각 notifier가 내부적으로 어떻게 작동하는지 알 필요가 없다는 점입니다. 단순히 interface의 notify function을 Call하면 올바른 구현이 실행됩니다. header file에서 include guards를 사용하는 것을 잊지 마세요.
직접 해보기
#include <stdio.h>
#include "notifier.h"
int main() {
int type;
char message[256];
// 알림 유형 읽기 (1은 이메일, 2는 SMS)
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 생성
// type 1에는 create_email_notifier() 사용
// type 2에는 create_sms_notifier() 사용
// TODO: 인터페이스를 통해 notify 함수 호출
// notifier.notify(message);
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C 컴파일러