CS/개념

OOP (Object-Oriented Programming)

tae-woong 2025. 10. 7. 22:53
OOP란 무엇인가?

OOP(Object-Oriented Programming)란 현실 세계의 사물이나 개념을 객체(Object)로 모델링하고, 이 객체들 간의 상호작용을 통해 프로그램을 설계하고 개발하는 프로그래밍 패러다임입니다. 쉽게 말해, 연관 있는 데이터(변수)와 그 데이터를 처리하는 함수(메서드)를 하나의 '객체'라는 덩어리로 묶어서 관리하는 방식입니다. 이를 통해 코드의 재사용성을 높이고, 유지보수와 확장을 훨씬 효율적으로 할 수 있습니다.

 

Entity vs Object?
구분 설명 예시
개체 (Entity) 현실 세계에 존재하는 구체적인 대상 자체 실제로 존재하는 "내 캐릭터", "슬라임 몬스터"
객체 (Object) 개체를 프로그래밍 세계에서 표현한 것
데이터와 기능을 묶은 단위
Player myPlayer = new Player();
Slime slime = new Slime();

 

OOP의 4대 특징

1️⃣ 추상화 (Abstraction)

불필요한 세부 정보는 숨기고, 핵심적인 공통 기능만 드러내는 것

무엇을(What) 하는가에 초점을 맞춥니다. 모든 캐릭터는 '공격'하고 '이동'한다는 공통점이 있습니다. 이 '공격'과 '이동'이라는 개념의 뼈대를 만드는 것이 추상화입니다.

 

🎮 게임 개발 예시 : Character라는 추상 클래스를 만들어 모든 캐릭터가 가져야 할 Attack(), Move() 같은 공통 메서드를 정의합니다. 실제 공격 방식(검, 활, 마법)은 각 직업 클래스가 구체적으로 구현하도록 맡깁니다.

// "모든 캐릭터는 공격 기능이 있어야 한다"는 뼈대만 제공
public abstract class Character 
{
    public abstract void Attack(); // 내용은 자식 클래스가 채운다
}

public class Warrior : Character 
{
    public override void Attack() 
    {
        // 전사는 "검으로 공격"하는 세부 내용을 구현
        Debug.Log("검으로 공격!");
    }
}

public class Archer : Character 
{
    public override void Attack() 
    {
        // 궁수는 "활로 공격"하는 세부 내용을 구현
        Debug.Log("활로 공격!");
    }
}

2️⃣ 캡슐화 (Encapsulation)

데이터(속성)와 메서드를 하나로 묶고, 외부에서 데이터에 직접 접근하지 못하도록 보호하는 것(정보 은닉 + 접근 제한)

 

객체의 내부 구현을 숨겨서, 외부에서는 오직 허락된 메서드를 통해서만 데이터에 접근할 수 있게 합니다. 이를 통해 데이터의 무결성을 지키고 의도치 않은 수정을 방지할 수 있습니다.

 

🎮 게임 개발 예시 : 플레이어의 체력(hp)은 매우 중요한 데이터입니다. 만약 hp가 public이라면, 다른 코드에서 player.hp = 9999; 같은 치트성 코드로 쉽게 조작할 수 있습니다. 이를 막기 위해 hp는 private으로 숨기고, TakeDamage()라는 정해진 메서드를 통해서만 체력을 변경할 수 있게 합니다.

public class Player 
{
    private int hp = 100; // 외부에서 직접 접근 불가!

    // 오직 이 메서드를 통해서만 hp를 변경할 수 있다.
    public void TakeDamage(int damage)
    {
        if (damage > 0) 
        {
            hp -= damage;
            Debug.Log($"피해를 입었습니다. 현재 체력: {hp}");
        }
    }
}

3️⃣ 상속 (Inheritance)

기존 클래스(부모)의 속성과 메서드를 새로운 클래스(자식)가 물려받아 재사용하거나 확장하는 것

코드 중복을 줄이고, 클래스 간의 관계를 논리적으로 설정하여 코드의 생산성을 높입니다.

 

🎮 게임 개발 예시 : 모든 몬스터가 공통적으로 가지는 ChasePlayer() 기능을 Enemy 부모 클래스에 만듭니다. Goblin, Orc 같은 자식 클래스는 이 기능을 그대로 물려받아 사용하고, 각자만의 고유한 기능ThrowRock(), SwingAxe()만 추가로 구현하면 됩니다.

// 모든 적의 공통 기능 정의
public class Enemy 
{
    public int hp;
    public void ChasePlayer() 
    {
        Debug.Log("플레이어를 쫓아갑니다.");
    }
}

// Enemy를 상속받아 ChasePlayer() 기능을 그대로 사용
public class Goblin : Enemy 
{
    public void ThrowRock() 
    {
        Debug.Log("돌을 던집니다!");
    }
}

// Enemy를 상속받아 ChasePlayer() 기능을 그대로 사용
public class Orc : Enemy 
{
    public void SwingAxe() 
    {
        Debug.Log("도끼를 휘두릅니다!");
    }
}

4️⃣ 다형성 (Polymorphism)

동일한 이름의 메서드가 객체의 실제 타입에 따라 다른 방식으로 동작하는 것

"어떻게(How) 다르게 하는가"에 초점을 맞춥니다. 오버라이딩(Overriding)과 오버로딩(Overloading)을 통해 구현됩니다. 특히 오버라이딩은 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것으로, 다형성의 핵심입니다.

 

🎮 게임 개발 예시 : 부대 단위의 몬스터를 관리한다고 상상해 봅시다. List<Enemy>에 고블린, 오크 등 다양한 몬스터를 담아두고, 반복문을 돌면서 enemy.Attack()을 호출하면 각 몬스터의 타입에 맞는 공격(돌 던지기, 도끼 휘두르기)이 실행됩니다. 관리자는 몬스터의 종류를 일일이 신경 쓸 필요 없이 '공격하라'는 명령만 내리면 됩니다.

public class Enemy 
{
    public virtual void Attack() 
    {
        Debug.Log("기본 공격!");
    }
}

public class Goblin : Enemy 
{
	// 부모의 Attack()을 재정의
    public override void Attack() 
    {
        Debug.Log("돌 던지기 공격!");
    }
}

public class Orc : Enemy 
{
	// 부모의 Attack()을 재정의
    public override void Attack() 
    { 
        Debug.Log("도끼 휘두르기 공격!");
    }
}

// 사용 예시
List<Enemy> enemyTroop = new List<Enemy>();
enemyTroop.Add(new Goblin());
enemyTroop.Add(new Orc());

foreach (Enemy enemy in enemyTroop) 
{
    enemy.Attack(); // 같은 코드지만, 고블린과 오크가 다르게 행동한다.
}

 

 

'CS > 개념' 카테고리의 다른 글

Polling / Interrupt  (0) 2025.10.22
Call by Value / Call by Sharing / Call by Reference  (0) 2025.10.20
오버로딩(Overloading)과 오버라이딩(Overriding)  (0) 2025.10.08