객체지향 프로그래밍(OOP)에 있어 항상 등장하는 개념들... 클래스인터페이스

이 둘의 차이점은 한번에 이해해보자!

 

Q1. 클래스(Class)인터페이스(Interface)의 차이

클래스와 인터페이스의 차이

 

클래스객체를 만들려는 설계도, 틀이라고 하면

인터페이스 클래스가 지켜야할 규칙을 정의한다.

 

예시로 자동차 클래스자동차 속성(색깔, 속도, 연료 등)이 있고,

자동차 인터페이스자동차가 반드시 있어야 하는 기능(시동 on / off, 이동기능들)들을 정의하는 것!

 


- 코드로 보는 클래스의 특징 (c#)

예시 코드는 모든 게임 유닛의 Base가 되는 BaseUnit 클래스가 있고

BaseUnit을 상속받아서 각각 플레이어 캐릭터적 캐릭터를 만드는 간단한 예시이다.

 

상황은 간단하다. 플레이어랑 적 캐릭터가 서로를 향해 공격을 한다!

    // 기본적인 유닛 클래스
    class BaseUnit
    {
        public string Name { get; set; }
        public int maxHp { get; set; }
        public int curHp;

        public BaseUnit(string name, int health)
        {
            Name = name;
            maxHp = health;
            curHp = maxHp;
        }

        public virtual void TakeAction(BaseUnit target)
        {
            Console.WriteLine($"{Name}의 행동");
        }

        public void TakeDamage(int damage)
        {
            curHp -= damage;
            Console.WriteLine($"{Name}가 {damage}의 피해를 입었다. {Name}의 체력: {curHp}\n");
        }
    }


    // 플레이어 클래스 (BaseUnit 상속)
    class Player : BaseUnit
    {
        public Player(string name, int health) : base(name, health) { }

        public override void TakeAction(BaseUnit target) 
        {
            Attack(target);
        }

        public void Attack(BaseUnit target)
        {
            Console.WriteLine($"{Name}가 {target.Name}을 공격했다!");
            target.TakeDamage(10);
        }
    }

    // 적 캐릭터 클래스 (BaseUnit 상속)
    class Enemy : BaseUnit
    {
        public Enemy(string name, int health) : base(name, health) { }

        public override void TakeAction(BaseUnit target)
        {
            Console.WriteLine($"{Name}의 공격! {target.Name}는 피해를 입었다.");
            target.TakeDamage(5);
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Player player = new Player("주인공", 100);
            Enemy enemy = new Enemy("고블린", 50);

            player.TakeAction(enemy);
            enemy.TakeAction(player);
        }
    }

 

클래스속성과 메서드를 만들 수 있다.

사용할 때는 객체를 생성해서 사용하며, 상속을 통해서 클래스를 확장시킬 수 있다.


- 코드로 보는 인터페이스의 특징

이번에는 피해를 받는 인터페이스를 정의하고, 피해 인터페이스BaseUnit이 상속받았다.

 

상황은 이번에도 똑같이 서로를 향해 공격을 가하는데 적 캐릭터가 가하는 공격은 방패가 피해를 받는다!

namespace Class_Interface
{

    // 공격을 받는 인터페이스 정의
    interface IAttackable
    {
        void TakeDamage(int damage);
    }

    // 기본적인 유닛 클래스
    class BaseUnit : IAttackable
    {
        public string Name { get; set; }
        public int maxHp { get; set; }
        public int curHp;

        public BaseUnit(string name, int health)
        {
            Name = name;
            maxHp = health;
            curHp = maxHp;
        }

        public virtual void TakeAction(IAttackable target)
        {
            Console.WriteLine($"{Name}의 행동");
        }

        public void TakeDamage(int damage)
        {
            curHp -= damage;
            Console.WriteLine($"{Name}가 {damage}의 피해를 입었다. {Name}의 체력: {curHp}\n");
        }
    }


    // 플레이어 클래스 (BaseUnit 상속)
    class Player : BaseUnit
    {
        public Player(string name, int health) : base(name, health) { }

        public override void TakeAction(IAttackable target) 
        {
            Attack(target);
        }

        public void Attack(IAttackable target)
        {
            Console.WriteLine($"{Name}의 공격!");
            target.TakeDamage(10);
        }
    }

    // 적 캐릭터 클래스 (BaseUnit 상속)
    class Enemy : BaseUnit
    {
        public Enemy(string name, int health) : base(name, health) { }

        public override void TakeAction(IAttackable target)
        {
            Console.WriteLine($"{Name}의 공격!");
            target.TakeDamage(5);
        }
    }

    // 방어구 클래스 (IAttackable 인터페이스 구현)
    class Shield : IAttackable
    {
        public int Durability { get; set; }

        public Shield(int durability)
        {
            Durability = durability;
        }

        public void TakeDamage(int damage)
        {
            Durability -= damage;
            Console.WriteLine($"방패가 {damage}의 피해를 흡수했습니다! 남은 내구도: {Durability}");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Player player = new Player("주인공", 100);
            Enemy enemy = new Enemy("고블린", 50);
            Shield shield = new Shield(30);

            player.TakeAction(enemy);
            enemy.TakeAction(shield);
        }
    }
}

인터페이스의 실행 결과

 

클래스와 다른점은 인터페이스는 공격 선언만 하고, 내용은 없다.

하지만 클래스인터페이스를 구현 (implement) 한다면공격 기능은 반드시 구현시켜야 한다!


 

상속(Extends)구현(Implements)의 차이점만 이해한다면 좀 더 알기 쉬워진다

  클래스 상속 인터페이스 구현
관계 부모-자식 관계 (is-a 관계) 능력을 받는다 (Can-do 관계)
개수 단일 상속만 가능 (1개) 다중 구현이 가능 (여러개)
내용 부모의 속성/메서드를 물려받음 메서드 선언만 약속하고
구현은 하위에서 담당!
목적 코드 재사용성 (확장성) 공통된 행위 약속

 

 

아주 간단하게 정리하자면

 

  • 클래스는 "나는 누구?이다." (플레이어, 적 개체를 생성한다)
  • 인터페이스는 "나는 이 무언가?를 할 수 있다." ('공격을 받을 수 있다' 정의를 설정한다)

 

+ Recent posts