본문 바로가기
C#

Data 관리 클래스를 static 으로 만들어야 하는 이유

by Oz Driver 2025. 11. 15.

1. 초기 구조의 한계

처음에는 다음과 같이 게임 규칙과 로직이 모두 MainForm 안에 포함되어 있었습니다.

public partial class MainForm : Form
{
    int stageIndex = 0;

    StageData[] stageData = new StageData[3];

    int ballSpeedX = 7;
    int ballSpeedY = 7;

    int blockRow = 3;
    int blockColumn = 5;
    int blockWidth = 100;
}

 

이 구조에서는 다음과 같은 문제가 발생합니다.

  • 스테이지 데이터와 게임 로직이 섞여 있어 가독성이 저하됩니다.
  • Stage 관련 정보를 수정하려면 반드시 MainForm 내부를 수정해야 합니다.
  • 다른 화면(Form)에서 동일 데이터를 공유하려면 또 복사하거나 별도 관리가 필요합니다.

즉, 데이터와 로직이 분리되지 않아 확장성과 유지보수성이 떨어지는 구조가 됩니다.

 

2. GameData 클래스로 데이터만 분리한 이유

게임의 규칙(난이도, 블록 배치, 공 속도 등)을 담당하는 부분을 따로 분리하면 다음과 같은 장점이 생깁니다.

로직과 데이터의 명확한 분리

GameData에는 게임 규칙만 존재하고, MainForm에는 움직임 및 충돌 처리와 같은 순수 로직만 남게 됩니다. 이를 통해 코드를 읽을 때 목적이 명확하게 구분됩니다.

규칙 변경이 쉬워짐

스테이지 개수, 공 속도, 블록 개수 등은 게임 규칙에 해당하며, 이러한 데이터는 GameData만 수정하면 전체 게임에 반영됩니다. 로직 코드를 건드릴 필요가 없습니다.

여러 화면에서 동일하게 접근 가능

TitleForm, ResultForm, OptionForm 등 앞으로 화면이 늘어날 때 데이터를 공유하기가 훨씬 편해집니다.

 

3. 왜 GameData를 static 클래스로 만들었는가

데이터 분리뿐 아니라 static 클래스로 만든 이유도 중요합니다.

new GameData() 방식의 문제점

만약 일반 클래스로 GameData를 만든다면, 다음과 같이 사용해야 합니다.

GameData data = new GameData();
MainForm form = new MainForm(data);

 

이 방식에서는 다음 문제가 생깁니다.

  • GameData를 어디에서 new 할지 결정해야 합니다.
    • Program.cs?
    • MainForm 내부?
    • TitleForm에서?
  • 여러 Form에서 GameData 인스턴스를 공유하기 어렵습니다.
    생성자를 통해 계속 전달하거나 전역 변수처럼 관리해야 합니다.
  • 실수로 new를 여러 번 생성할 위험이 있습니다.
    • 서로 다른 GameData 인스턴스가 존재하면 데이터 불일치 문제가 발생합니다.

즉, “전역에서 하나만 존재해야 하는 데이터”를 일반 클래스로 만들면 오히려 관리 난이도가 높아집니다.

 

static 클래스로 만들면 해결되는 점

static class는 다음과 같은 특징을 가집니다.

  • 인스턴스 생성이 불가능합니다. (new GameData() 금지)
  • 어디서든 바로 접근할 수 있습니다.
  • static 생성자는 딱 한 번 자동으로 호출되며, 초기화 시점을 C# 런타임이 보장합니다.

즉, 게임의 규칙처럼 전역에서 하나만 존재해야 하는 데이터는 static이 가장 자연스러운 구조입니다.

internal static class GameData
{
    public static StageData[] stageData;
    public static int StageCount { get; set; }

    public static StageData CurrentStage => stageData[StageCount];

    static GameData()
    {
        StageCount = 0;
        stageData = new StageData[3]
        {
            new StageData() { ballSpeed = 5, blockRow = 3, blockColumn = 5, blockWidth = 100 },
            new StageData() { ballSpeed = 7, blockRow = 4, blockColumn = 6, blockWidth = 80 },
            new StageData() { ballSpeed = 9, blockRow = 5, blockColumn = 7, blockWidth = 60 }
        };
    }
}

 

 

4. MainForm에서는 이렇게 간단하게 사용 가능

ballSpeedX = GameData.CurrentStage.ballSpeed;
ballSpeedY = GameData.CurrentStage.ballSpeed;
blockRow   = GameData.CurrentStage.blockRow;
blockColumn= GameData.CurrentStage.blockColumn;
blockWidth = GameData.CurrentStage.blockWidth;

 

이제 메인 로직(MainForm)은 규칙을 신경 쓸 필요가 없습니다.
단지 “현재 스테이지의 규칙을 읽어와서 적용한다”는 행위만 수행하면 됩니다.

 

5. 결론

  • 게임 규칙과 로직은 분리하는 것이 유지보수에 가장 유리합니다.
  • 전역에서 하나만 존재해야 하는 규칙 데이터는 static 클래스로 관리하는 것이 가장 자연스럽습니다.
  • static 생성자는 자동으로 한 번만 호출되기 때문에 초기화 타이밍에 대한 고민이 사라집니다.
  • 여러 Form이나 클래스에서 손쉽게 접근할 수 있으며, 데이터 일관성이 보장됩니다.

따라서 GameData를 static 클래스로 구성하는 방식은 WinForms 기반 게임 구조에서 매우 실용적이며, 확장성 있는 설계 방식이라고 할 수 있습니다.