Menu
Coddy logo textTech

싱글톤 패턴

Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 90번째.

Singleton 패턴은 클래스에 인스턴스가 전체 애플리케이션에서 단 하나만 존재하도록 보장하며, 이에 대한 전역적인 접근 지점을 제공합니다. 이는 설정 관리자, 데이터베이스 연결 또는 로깅 서비스와 같이 시스템 전체에서 동작을 조정하기 위해 정확히 하나의 객체가 필요할 때 유용합니다.

Dart에서 프라이빗 정적 인스턴스와 결합된 팩토리 생성자를 사용하여 싱글톤(Singleton)을 구현할 수 있습니다:

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Private named constructor
  // 프라이빗 명명 생성자
  AppConfig._internal();
  
  // Factory constructor returns the same instance
  // 팩토리 생성자는 동일한 인스턴스를 반환합니다.
  factory AppConfig() {
    return _instance;
  }
}

void main() {
  var config1 = AppConfig();
  var config2 = AppConfig();
  
  config1.appName = 'UpdatedApp';
  
  print(config2.appName);  // UpdatedApp
  print(identical(config1, config2));  // true
}

프라이빗 생성자인 _internal()은 외부 인스턴스화를 방지합니다. 정적(static) _instance 필드는 클래스가 로드될 때 한 번 생성되는 단일 인스턴스를 보유합니다. AppConfig()를 호출할 때마다 이 동일한 인스턴스를 반환하므로, 하나의 참조를 통해 변경된 사항은 모든 곳에 반영됩니다.

싱글톤(Singleton)은 가급적 드물게 사용하세요. 싱글톤은 전역 상태를 도입하여 테스트를 더 어렵게 만들 수 있습니다. 싱글톤은 애플리케이션 전체에서 일관된 상태를 유지해야 하는 진정한 공유 리소스에 가장 적합합니다.

challenge icon

챌린지

쉬움

싱글톤 패턴을 사용하여 게임 설정 관리자를 만들어 봅시다! 애플리케이션 전체에서 단 하나의 게임 설정 인스턴스만 존재하도록 보장하는 시스템을 만들어, 게임의 모든 부분에서 동일한 구성을 공유하도록 할 것입니다.

코드를 두 개의 파일로 구성합니다:

  • game_settings.dart: 싱글톤 패턴을 구현하는 GameSettings 클래스를 생성합니다. 설정 관리자는 다음을 포함해야 합니다:
    • 단일 GameSettings 객체를 보유하는 private static final 인스턴스
    • 외부 인스턴스화를 방지하기 위한 private 명명된 생성자(named constructor)
    • 항상 동일한 인스턴스를 반환하는 팩토리 생성자(factory constructor)
    • 세 개의 설정 필드: difficulty (String, 기본값: "Normal"), soundEnabled (bool, 기본값: true), playerName (String, 기본값: "Player1")
    • 현재 설정을 Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off] 형식으로 출력하는 displaySettings() 메서드 (soundEnabled가 true이면 "on", false이면 "off"를 출력)
  • main.dart: 게임 설정을 임포트하고 싱글톤이 올바르게 작동하는지 증명합니다:
    • 설정 인스턴스를 가져와 settings1이라고 부릅니다.
    • displaySettings()를 호출하여 기본값을 표시합니다.
    • 설정을 수정합니다: playerName을 "Hero"로, difficulty를 "Hard"로, soundEnabled를 false로 변경합니다.
    • 설정에 대한 또 다른 참조를 가져와 settings2라고 부릅니다.
    • settings2에서 displaySettings()를 호출하여 settings1을 통해 변경된 내용이 반영되었는지 확인합니다.
    • settings1settings2가 동일한지 Same instance: [true/false] 형식을 사용하여 출력합니다.

이는 싱글톤의 핵심적인 장점을 보여줍니다. 인스턴스가 하나뿐이기 때문에 애플리케이션의 어느 곳에서든 변경한 내용이 다른 모든 곳에서 즉시 확인 가능합니다!

예상 출력:

Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: true

치트 시트

싱글톤 패턴(Singleton pattern)은 애플리케이션 전체에서 클래스의 인스턴스가 단 하나만 존재하도록 보장하며, 해당 인스턴스에 접근할 수 있는 전역적인 지점을 제공합니다.

Dart에서는 팩토리 생성자(factory constructor)와 프라이빗 정적 인스턴스(private static instance)를 결합하여 싱글톤을 구현합니다:

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Private named constructor
  AppConfig._internal();
  
  // Factory constructor returns the same instance
  factory AppConfig() {
    return _instance;
  }
}

주요 구성 요소:

  • static final _instance: 클래스가 로드될 때 한 번 생성되는 단일 인스턴스를 보유합니다
  • _internal(): 프라이빗 생성자로 외부에서의 인스턴스화를 방지합니다
  • factory AppConfig(): 매번 동일한 인스턴스를 반환합니다

사용 예시:

var config1 = AppConfig();
var config2 = AppConfig();

config1.appName = 'UpdatedApp';

print(config2.appName);  // UpdatedApp
print(identical(config1, config2));  // true

모든 참조가 동일한 인스턴스를 가리키기 때문에 하나의 참조를 통해 변경된 사항은 모든 곳에서 확인할 수 있습니다.

직접 해보기

import 'game_settings.dart';

void main() {
  // TODO: settings 인스턴스를 가져와서 settings1이라고 부릅니다.
  
  // TODO: 기본값을 표시하기 위해 displaySettings()를 호출합니다.
  
  // TODO: 설정을 수정합니다:
  // - playerName을 "Hero"로 변경합니다.
  // - difficulty를 "Hard"로 변경합니다.
  // - soundEnabled를 false로 변경합니다.
  
  // TODO: settings에 대한 또 다른 참조를 가져와서 settings2라고 부릅니다.
  
  // TODO: 변경 사항이 반영되었는지 확인하기 위해 settings2에서 displaySettings()를 호출합니다.
  
  // TODO: settings1과 settings2가 동일한지 출력합니다.
  // 형식: Same instance: [true/false]
}
quiz icon실력 점검

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

객체 지향 프로그래밍의 모든 레슨