스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록

2024.04.24 TIL - Item 클래스의 상속, 인터페이스, 다중 상속

테크러너 2024. 4. 24.

Item 을 인터페이스로 만들었을 때 문제점

// 아이템을 사용할 수 있는 인터페이스
public interface IUsable
{
    void Use();
}

// 아이템 클래스
public class Item : IUsable
{
    public string Name { get; set; }

    public void Use()
    {
        Console.WriteLine("아이템 {0}을 사용했습니다.", Name);
    }
}

강의에서 위와 같이 아이템을 인터페이스로 사용하는 예시를 보고 개인 프로젝트에도 적용해봤다.

 

그런데 점점 거대해져가는 클래스..!(눈갱 주의) ▼

더보기
// 아이템 인터페이스
    public class IItem
    {
        int equipped { get; }
        string name { get; }
        int stat { get; }
        string description { get; }
        string DisplayItemState();
    }

    // 방어구
    public class Armor : IItem
    {
        public int equipped { get; }
        public string name { get; }
        public int stat { get; }
        public string description { get; }

        public Armor(int _equipped, string _name, int _stat, string _description)
        {
            equipped = _equipped;
            name = _name;
            stat = _stat;
            description = _description;
        }
        public string DisplayItemState()
        {
            if (equipped == 1)
            {
                return "[E]";
            }
            else
            {
                return " ";
            }
        }
    }

    // 무기
    public class Weapon : IItem
    {
        public int equipped { get; }
        public string name { get; }
        public int stat { get; }
        public string description { get; }

        public Weapon(int _equipped, string _name, int _stat, string _description)
        {
            equipped = _equipped;
            name = _name;
            stat = _stat;
            description = _description;
        }
        public string DisplayItemState()
        {
            if (equipped == 1)
            {
                return "[E]";
            }
            else
            {
                return " ";
            }
        }
    }

내가 하고 싶었던건 아이템마다 '착용시 어떤 스탯이 변경되는지' 만 다르게 할뿐... 아이템의 기본적인 정보들은 다 같았다.

 

 

거대해진 클래스.. 해결법은?

코드가 좀 더 간결해지기 위해서 인터페이스 방식이 아닌 상속 관계를 만들기로 했다.

 

// 아이템 클래스
public class Item
{
    public int equipped { get; private set; }
    public string name { get; private set; }
    public int stat { get; private set; }
    public string description { get; private set; }

    public Item(int _equipped, string _name, int _stat, string _description)
    {
        equipped = _equipped;
        name = _name;
        stat = _stat;
        description = _description;
    }

    public virtual string DisplayItemState()
    {
        if (equipped == 1)
        {
            return "[E]";
        }
        else
        {
            return " ";
        }
    }
}

// 아이템 스탯 변경 인터페이스
public interface IChangeStat
{
    void ChangeStat(Character character);
}

// 방어구 클래스
public class Armor : Item, IChangeStat
{
    public Armor(int _equipped, string _name, int _stat, string _description)
        : base(_equipped, _name, _stat, _description)
    {       
    }       
    public void ChangeStat(Character character)
    {
        // 방어력 스탯 변경
        character.ChangeDefensePower(stat);
    }
}

// 무기 클래스
public class Weapon : Item, IChangeStat
{
    public Weapon(int _equipped, string _name, int _stat, string _description)
        : base(_equipped, _name, _stat, _description)
    {            
    }
    public void ChangeStat(Character character)
    {
        // 공격력 스탯 변경
        character.ChangeAttackPower(stat);
    }
}

`Item` 클래스를 부모로 두고, 자식 클래스들은 ' 착용시 어떤 스탯이 변경되는지 ' 만 구현하도록 했다.

 

 

다른 시각에서 인터페이스 사용해보기

아직까지 인터페이스 개념이 제대로 익혀지지 않은 것 같다.

그래도 배운건 써보고 싶어서 고민을 해봤는데

 

`Item` 클래스에서는 `ChangeStat()` 메소드가 필요없고, 자식 클래스들은 필요하다.

그럼 자식 클래스에게 `ChangeStat()` 메소드를 만들라는 강제성을 부여하도록 인터페이스를 사용하면 되지 않는가!

 

적용한 결과▼

    // 아이템 스탯 변경 인터페이스
    public interface IChangeStat
    {
        void ChangeStat(Character character);
    }

    // 방어구 클래스
    public class Armor : Item, IChangeStat
    {
        public Armor(int _equipped, string _name, int _stat, string _description)
            : base(_equipped, _name, _stat, _description)
        {       
        }       
        public void ChangeStat(Character character)
        {
            // 방어력 스탯 변경
            character.ChangeDefensePower(stat);
        }
    }

    // 무기 클래스
    public class Weapon : Item, IChangeStat
    {
        public Weapon(int _equipped, string _name, int _stat, string _description)
            : base(_equipped, _name, _stat, _description)
        {            
        }
        public void ChangeStat(Character character)
        {
            // 공격력 스탯 변경
            character.ChangeAttackPower(stat);
        }
    }

 

 

 

여기서 더 추가 구현해볼 것이 생각났다. 강의 자료를 보고 생각해냈다.

public interface IItemPickable
{
    void PickUp();
}

// 인터페이스 2
public interface IDroppable
{
    void Drop();
}

// 아이템 클래스
public class Item : IItemPickable, IDroppable
{
    public string Name { get; set; }

    public void PickUp()
    {
        Console.WriteLine("아이템 {0}을 주웠습니다.", Name);
    }

    public void Drop()
    {
        Console.WriteLine("아이템 {0}을 버렸습니다.", Name);
    }
}

강의 자료에서 위와 같이 다중 상속으로 인터페이스를 활용한 예제가 있었다.

지금은 아이템 스탯 변경 인터페이스를 뒀는데 예제를 보니 깨달았다. 아이템 장착과 해제을 따로 두어야 한다는것을...

 

 

아이템 스탯 증가 → 아이템 장착과 해제로 수정하기

그래서 다시 코드를 수정해봤다.

수정된 코드▼

    // 아이템 스탯 증가 인터페이스
    public interface IEquipItem
    {
        void EquipItem(Character character);
    }

    // 아이템 스탯 감소 인터페이스
    public interface IUnequipItem
    {
        void UnequipItem(Character character);
    }

    // 방어구 클래스
    public class Armor : Item, IEquipItem, IUnequipItem
    {
        public Armor(int _equipped, string _name, int _stat, string _description)
            : base(_equipped, _name, _stat, _description)
        {       
        }
        // 방어력 스탯 증가
        public void EquipItem(Character character)
        {
            character.IncreaseDefense(stat);
        }

        // 방어력 스탯 감소
        public void UnequipItem(Character character)
        {
            character.DecreaseDefense(stat);
        }
    }

    // 무기 클래스
    public class Weapon : Item, IEquipItem, IUnequipItem
    {
        public Weapon(int _equipped, string _name, int _stat, string _description)
            : base(_equipped, _name, _stat, _description)
        {            
        }
        // 공격력 스탯 증가
        public void EquipItem(Character character)
        {           
            character.IncreaseAttack(stat);
        }

        // 공격력 스탯 감소
        public void UnequipItem(Character character)
        {   
            character.DecreaseAttack(stat);
        }
    }

 

다중 상속 인터페이스를 두면 아이템을 장착할것인지 해제할것인지가 쉽게 알 수 있어 가독성이 좋아지는 것 같다.

가독성 예시▼

    public void InteractWithItem(IItemPickable item)
    {
        item.PickUp();
    }

    public void DropItem(IDroppable item)
    {
        item.Drop();
    }

`IItemPickable item` `IDroppable item`을 봤을 때 뭘할 것인지 한 눈에 알 수 있다!..

 

반응형

댓글