싱글톤 패턴
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 91번째.
Singleton 패턴은 클래스가 전체 프로그램에서 하나의 인스턴스만 갖도록 보장하고, 해당 인스턴스에 대한 전역 액세스 지점을 제공합니다. 이는 구성 관리자, 로거 또는 데이터베이스 연결 풀처럼 공유되어야 하는 리소스에 유용합니다.
핵심 아이디어는 constructor를 private으로 만들어 아무도 인스턴스를 직접 생성할 수 없게 한 다음, 단일 인스턴스를 반환하는 static 메서드를 제공하는 것입니다:
#include <iostream>
#include <string>
class Logger {
private:
std::string logFile;
// 비공개 생성자 - 직접 인스턴스화를 방지
Logger() : logFile("app.log") {}
// 복사 생성자와 대입 연산자 삭제
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
public:
// 단일 인스턴스에 접근하기 위한 정적 메서드
static Logger& getInstance() {
static Logger instance; // 한 번 생성되며, 프로그램이 종료될 때까지 유지됨
return instance;
}
void log(const std::string& message) {
std::cout << "[LOG] " << message << "\n";
}
};
int main() {
Logger::getInstance().log("Application started");
Logger& logger = Logger::getInstance();
logger.log("Processing data");
}getInstance() 내부의 static Logger instance는 "매직 static"이라고 하는 C++11 기능으로, 스레드로부터 안전하며 한 번만 초기화되도록 보장됩니다. 복사 생성자와 대입 연산자를 삭제함으로써 누구도 싱글턴의 복사본을 만들 수 없도록 방지합니다.
Singleton은 신중하게 사용하세요. Singleton은 전역 상태를 도입하여 테스트를 더 어렵게 만들 수 있습니다. 여러 인스턴스가 있으면 문제가 발생하는 진정으로 공유되는 리소스에 가장 적합합니다.
챌린지
쉬움게임 애플리케이션의 구성을 관리하는 GameSettings 싱글턴을 만들어 보겠습니다. 이는 Singleton 패턴을 사용하기에 완벽한 사례입니다. 게임의 모든 부분에서 액세스할 수 있는 설정 관리자를 정확히 하나만 두어 전체에서 일관된 구성을 유지하려는 것입니다.
코드를 세 개의 파일로 구성합니다.
GameSettings.h: 게임 구성을 관리하는 싱글턴 클래스를 정의합니다.GameSettings클래스는 세 가지 설정을 private 멤버로 저장해야 합니다.difficulty(문자열),volume(0-100 범위의 정수),fullscreen(불리언)입니다. 기본값은"Normal",50,false로 초기화합니다.Singleton 패턴을 올바르게 Implement합니다.
- 생성자를 private으로 만듭니다.
- 복사 생성자와 대입 연산자를 Delete합니다.
- 단일 인스턴스에 대한 참조를 반환하는 정적
getInstance()메서드를 제공합니다.
설정과 상호 작용할 수 있도록 다음 public 메서드를 추가합니다.
setDifficulty(const std::string& diff): 난이도를 업데이트합니다.setVolume(int vol): 볼륨을 업데이트합니다.setFullscreen(bool fs): 전체 화면 모드를 업데이트합니다.displaySettings(): 현재 설정을 모두 출력합니다.
GameModule.h: 싱글턴에 액세스하는 별도의 모듈을 Create합니다.프리셋 이름(문자열)을 받는
applyGamePreset이라는 함수를 정의합니다. 이 함수는GameSettings싱글턴에 액세스하고 프리셋에 따라 구성해야 합니다."casual": 난이도를"Easy"로, 볼륨을70으로, 전체 화면을false로 설정합니다."competitive": 난이도를"Hard"로, 볼륨을30으로, 전체 화면을true로 설정합니다.- 그 외의 프리셋: 기본 설정을 변경하지 않고 유지합니다.
이는 프로그램의 서로 다른 부분에서 동일한 싱글턴 인스턴스에 액세스하고 수정할 수 있음을 보여 줍니다.
main.cpp: 모든 요소를 함께 사용하여 싱글턴이 작동하는 모습을 보여 줍니다.두 개의 입력을 읽습니다.
- 프리셋 이름(문자열)
- 사용자 지정 볼륨 수준(정수)
먼저 싱글턴에서
displaySettings()를 호출하여 초기 기본 설정을 출력합니다. 그 뒤에 빈 줄을 출력합니다.그런 다음
applyGamePreset함수를 사용하여 프리셋을 적용하고 설정을 다시 출력합니다. 그 뒤에 빈 줄을 출력합니다.마지막으로 사용자 지정 입력 값으로 볼륨만 재정의하고 최종 설정을 출력합니다.
displaySettings() 메서드는 다음과 정확히 같은 형식으로 출력해야 합니다.
Difficulty: [value]
Volume: [value]
Fullscreen: [yes/no]예를 들어 입력이 casual과 85인 경우:
Difficulty: Normal
Volume: 50
Fullscreen: no
Difficulty: Easy
Volume: 70
Fullscreen: no
Difficulty: Easy
Volume: 85
Fullscreen: no입력이 competitive과 20인 경우:
Difficulty: Normal
Volume: 50
Fullscreen: no
Difficulty: Hard
Volume: 30
Fullscreen: yes
Difficulty: Hard
Volume: 20
Fullscreen: yesmain.cpp와 GameModule.h 모두 동일한 싱글턴 인스턴스에 액세스한다는 점에 주목하세요. 한 곳에서 변경한 내용이 모든 곳에서 보입니다. 이것이 게임 설정과 같은 공유 리소스에 Singleton 패턴을 사용하는 이유입니다.
직접 해보기
#include <iostream>
#include <string>
#include "GameSettings.h"
#include "GameModule.h"
using namespace std;
int main() {
// 입력 읽기
string presetName;
int customVolume;
cin >> presetName;
cin >> customVolume;
// TODO: GameSettings 싱글톤 인스턴스 가져오기
// TODO: 초기 기본 설정 표시
// TODO: 빈 줄 출력
// TODO: applyGamePreset 함수를 사용하여 프리셋 적용
// TODO: 프리셋 적용 후 설정 표시
// TODO: 빈 줄 출력
// TODO: customVolume으로 볼륨 재정의
// TODO: 최종 설정 표시
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C++ 컴파일러