이 Step에서 다루는 것

  • 게임/프로그램을 데이터(상태) + 로직(행동) 으로 나눠서 보는 이유
  • 절차 지향에서 규모가 커질수록 생기는 문제(함수 폭발, 책임 분산, 유지보수 비용 증가)
  • 객체 지향의 핵심 아이디어: 데이터와 로직을 한 덩어리(객체)로 묶어 책임을 모으기

학습 목표

  • “왜 OOP가 필요해지는지”를 확장/유지보수 관점으로 설명할 수 있다.
  • “함수 폭발”이 어떤 상황에서 발생하는지 예를 들 수 있다.
  • 객체(Object)를 “데이터 + 행동”으로 한 문장 정의할 수 있다.

데이터와 로직의 양분

  • 모든 게임·프로그램은 크게 데이터(상태)로직(행동) 으로 나눠서 볼 수 있습니다.
  • 데이터: “현재 상태” (예: HP/공격력/방어력/위치/인벤토리…)
  • 로직: 상태를 바꾸는 규칙 (예: 공격/회복/이동/피해/죽음 판정…)

규모가 커질수록 중요한 건 “코드가 길어지는 것” 자체가 아니라,

  • 변경하기 쉬운 구조인가?
  • 버그가 나면 추적이 쉬운 구조인가?

입니다.

절차 지향 (Procedural)의 한계

  • 절차 지향은 “함수(절차)”가 중심이 되고, 데이터는 함수에 의해 여기저기서 다뤄집니다.
  • (참고) C++에서도 절차 지향 스타일로 빠르게 만들 수 있습니다. 문제는 규모가 커질 때 구조가 무너지기 쉽다는 점입니다.

절차 지향 vs 객체 지향 비교 도표

┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│ 절차 지향 (Procedural)                    │ 객체 지향 (OOP)                                │
├───────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ [데이터]        [로직]                     │ [객체]                                          │
│  Knight    ←────  HealMe()                 │  Knight {                                       │
│  구조체           외부 함수                 │    _hp, _attack, _defence  ← 데이터              │
│  (분리)           (타입별로 각각 필요)      │    HealMe(), Attack()      ← 로직               │
│                                            │  }  (한 덩어리)                                 │
│ • HealMe(Knight*)   → Knight만             │ • k1.HealMe(10)  → 객체가 스스로                 │
│ • HealMe(Archer*)   → Archer용 별도        │ • 모든 타입이 동일 인터페이스                    │
│ • Fight(K*,K*)      → 3×3=9개 함수 폭발   │ • Fight(Player*, Player*)  하나로                │
└─────────────────────────────────────────────────────────────────────────────────────────────┘

핵심 문제(규모가 커질 때):

  • 함수 폭발: 타입이 늘어나면 “타입 조합”만큼 함수가 늘어날 수 있음
    (예: A vs B, A vs C, B vs C…)
  • 책임 분산: 데이터는 한 곳에 있고, 그 데이터를 바꾸는 로직은 여기저기 흩어져 “누가 언제 바꿨는지” 추적이 어려움
  • 불변식(invariant) 유지가 어려움: 예) HP는 0~Max 사이여야 하는데 외부 함수가 마음대로 만지면 규칙이 쉽게 깨짐
struct Knight {
    int hp;
    int attack;
    int defence;
};

void HealMe(Knight& k, int value) {
    k.hp += value;
}

학습 초반엔 이해가 쉽지만, 종류/규칙이 늘어날수록 “관리 책임”이 분산되어 유지보수 비용이 커지기 쉽습니다.

객체 지향 (OOP)으로의 전환

객체 지향의 핵심은 단순합니다.

  • 객체(Object) = 데이터(상태) + 행동(로직) 을 한 단위로 묶고
  • 그 객체가 자신의 상태를 “스스로” 관리하게 만들어
  • 변경/확장/디버깅 비용을 낮추는 방향으로 설계합니다.

예를 들어 “기사”는 HP/공격력 같은 데이터만 있는 게 아니라,
“회복/공격/피해/죽음 판정” 같은 규칙도 함께 묶여야 관리가 쉬워집니다.

class Knight {
public:
    void HealMe(int value) { _hp += value; } // (학습용) 이후엔 clamp 같은 규칙을 넣게 됨

    int _hp;
    int _attack;
    int _defence;
};

결론: 객체는 자신만의 상태와 행동을 함께 가지며, “관리 책임”을 객체 내부로 모으는 방향으로 설계가 바뀝니다.

체크 질문 (스스로 답해보기)

  • 타입이 늘어날 때, 절차 지향 방식에서 “함수 폭발”은 어떤 형태로 발생할까?
  • 데이터 규칙(예: HP는 0 미만이면 안 됨)을 외부 함수에 흩뿌려두면 왜 위험할까?
  • “객체 = 데이터 + 로직”을 TextRPG 예시(플레이어/몬스터)로 설명할 수 있을까?

profile
李家네_공부방

0개의 댓글