Menu
Coddy logo textTech

싱글톤 패턴

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

때로는 프로그램 전체에서 객체의 인스턴스가 정확히 하나만 필요한 경우가 있습니다 — 설정 관리자, 로깅 시스템 또는 데이터베이스 연결 등이 그 예입니다. 싱글톤 패턴(Singleton pattern)은 오직 하나의 인스턴스만 존재하도록 보장하며, 이에 대한 전역적인 접근 지점을 제공합니다.

C 언어에서는 소스 파일 내부의 static 변수를 사용하여 이를 구현합니다. 파일 범위에서의 static은 해당 변수가 해당 파일 내에서만 접근 가능하며(private) 프로그램의 수명 동안 유지됨을 의미한다는 점을 기억하세요. 게터(getter) 함수와 결합하여, 이것이 우리의 싱글톤(Singleton)을 만듭니다:

// config.c
#include "config.h"
#include <stdlib.h>

struct Config {
    int max_connections;
    int timeout;
};

static Config* instance = NULL;

Config* get_config(void) {
    if (instance == NULL) {
        instance = malloc(sizeof(Config));
        instance->max_connections = 100;
        instance->timeout = 30;
    }
    return instance;
}

마법은 get_config()에서 일어납니다. 첫 번째 호출은 인스턴스를 생성하고 초기화합니다. 그 이후의 모든 호출은 동일한 포인터를 반환합니다.

static 키워드는 instance가 함수 호출 간에 그 값을 유지하고 다른 파일로부터 숨겨진 상태를 유지하도록 보장합니다.

헤더에서 사용자는 getter 함수만 볼 수 있으며, 정적 변수에 직접 접근하거나 수정할 수 없습니다. get_config()를 얼마나 자주 또는 어디서 호출하든 관계없이 항상 동일한 객체를 얻게 됩니다.

challenge icon

챌린지

쉬움

싱글톤(Singleton) 패턴을 사용하여 애플리케이션 전반의 설정을 관리하는 Settings 모듈을 만들어 보겠습니다. 코드에서 설정을 몇 번 요청하든 관계없이 항상 동일한 인스턴스를 받아야 합니다.

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

  • settings.h: 전방 선언(forward declaration)을 사용하여 불투명한(opaque) Settings 타입을 선언합니다 (구조체 본체는 숨깁니다). 싱글톤 인스턴스에 대한 포인터를 반환하는 get_settings 함수와 두 가지 설정 값인 volume(정수) 및 brightness(정수)에 대한 getter 및 setter 함수를 선언합니다. 여기에는 인클루드 가드(include guards)가 필수적입니다.
  • settings.c: 실제 로직이 구현되는 곳입니다. volumebrightness 필드를 가진 실제 Settings 구조체를 정의합니다. 단일 인스턴스를 유지하기 위해 static 포인터 변수를 생성합니다 (NULL로 초기화). get_settings를 구현하여 첫 번째 호출 시 인스턴스를 할당하고 기본값(volume: 50, brightness: 75)으로 초기화하며, 이후 호출 시에는 단순히 기존 인스턴스를 반환하도록 합니다. 숨겨진 필드에 접근하고 수정할 수 있도록 getter와 setter를 구현합니다.
  • main.c: 싱글톤이 올바르게 작동하는지 증명합니다. 새로운 볼륨과 밝기 값을 나타내는 두 개의 정수를 입력받습니다. get_settings를 두 번 호출하여 결과를 두 개의 서로 다른 포인터 변수에 저장합니다. 첫 번째 포인터를 사용하여 입력받은 값으로 볼륨과 밝기를 업데이트합니다. 그런 다음 두 번째 포인터를 사용하여 두 값을 모두 가져와 출력합니다. 싱글톤이 작동한다면 한 포인터를 통해 변경한 내용이 다른 포인터를 통해서도 보여야 합니다.

프로그램은 두 개의 입력을 받습니다:

  1. 새로운 볼륨 값
  2. 새로운 밝기 값

한 포인터를 통해 수정하고 다른 포인터를 통해 읽은 후, 볼륨과 밝기를 별도의 줄에 출력하세요.

입력이 80100일 때의 예시 출력:

80
100

입력이 2560일 때의 예시 출력:

25
60

입력이 050일 때의 예시 출력:

0
50

핵심 통찰은 두 포인터가 메모리의 동일한 객체를 가리킨다는 것입니다. 이것이 싱글톤 패턴의 본질입니다. 소스 파일 내부의 정적(static) 변수는 단 하나의 인스턴스만 존재하도록 보장하며, 프로그램의 전체 수명 동안 유지됩니다.

치트 시트

싱글톤 패턴(Singleton pattern)은 프로그램 전체에서 객체의 인스턴스가 단 하나만 존재하도록 보장하며, 해당 인스턴스에 대한 전역적인 접근 지점을 제공합니다.

C 언어에서는 소스 파일 내부의 static 변수와 게터(getter) 함수를 결합하여 싱글톤을 구현합니다:

// config.c
#include "config.h"
#include <stdlib.h>

struct Config {
    int max_connections;
    int timeout;
};

static Config* instance = NULL;

Config* get_config(void) {
    if (instance == NULL) {
        instance = malloc(sizeof(Config));
        instance->max_connections = 100;
        instance->timeout = 30;
    }
    return instance;
}

주요 포인트:

  • 파일 범위(file scope)에서의 static 키워드는 변수를 해당 파일 내에서만 접근 가능하게(private) 만들고, 프로그램의 수명 동안 유지되도록 합니다.
  • 게터 함수는 첫 번째 호출 시 인스턴스가 NULL인지 확인하고, 인스턴스를 생성 및 초기화한 후 반환합니다.
  • 이후의 모든 호출은 동일한 포인터를 반환합니다.
  • 사용자는 헤더를 통해 게터 함수만 볼 수 있으며, 정적(static) 변수에 직접 접근하거나 수정할 수 없습니다.
  • 게터 함수를 얼마나 많이, 어디서 호출하든 항상 동일한 객체를 얻게 됩니다.

직접 해보기

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

int main() {
    int new_volume, new_brightness;
    scanf("%d", &new_volume);
    scanf("%d", &new_brightness);
    
    // TODO: get_settings를 두 번 호출하고 두 개의 서로 다른 포인터 변수에 저장하세요
    
    
    // TODO: 첫 번째 포인터를 사용하여 입력받은 값으로 volume과 brightness를 업데이트하세요
    
    
    // TODO: 두 번째 포인터를 사용하여 volume과 brightness를 가져와 출력하세요
    // (이는 두 포인터가 동일한 싱글톤 인스턴스를 가리키고 있음을 보여줍니다)
    
    
    return 0;
}
quiz icon실력 점검

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

Object Oriented Programming의 모든 레슨