02
15

인터페이스는 껍데기

 

 

class 부모클래스1 {}
class Child자식클래스 : 부모클래스1 {}

 

C#에서 클래스는 상속할 때 하나만 됩니다.

위에 코드에서 부모클래스2를 만들고 Child자식클래스에서 부모클래스1,2 둘 다 상속할려고 하면 에러가 뜹니다.

이러한 다중 상속을 하기 위해 인터페이스(Interface) 기능을 사용 합니다.

 

상속 개념도 궁금하면 아래 링크 클릭 ↓

유니티 C#의 필수 개념! 상속(inheritance)에 대해 알아보자

 

 


#1 인터페이스(Interface) 개념

 

인터페이스는 C#의 주요기능이자 객체 지향 코드입니다.

기본적으로 함수 정의, 프로퍼티(get,set) 정의 같은걸 구현없이 할 수 있도록 도와줍니다.

 

여기서 "구현없이" 라는 말이 중요합니다.

인터페이스 입장에선 구현 안해도 되니까 설계도 느낌으로 어떤걸 만들어야하는지만 알려줍니다.

 

예를 들어 들이나 건물같이 때리면 아파하거나 부숴지는 모션은 다르지만

결국엔 아파하면서 체력 깎인다는 함수를 구현해야만 하므로 DamageAble()같은 공통된 목적을 가진 함수를 만들어야만 합니다. 

 

예를 들어 IDamageAble이라는 인터페이스를 만들어서 안에다가 DamageAble();이라는 함수를 명시해놓기만 하면 됩니다.

이러면 들이나 건물같은 애들이 IDamageAble이라는 인터페이스를 상속해서 목적을 가진 설계도를 받아 디테일한 부분을 구현만 하면됩니다. 인터페이스는 다중 상속도 되니까 이런식의 공통적인걸 묶는걸 많이 할 수 있습니다.

 

인터페이스는 구현없이 명시만 하므로 인터페이스를 상속한 자식들은 반드시 명시한걸 재구현해야합니다.

이러한 인터페이스의 구현안해도 되는 특징은 복잡한 구조를 단순화 시키는 추상화와 비슷합니다.

하지만 추상 클래스인터페이스는 명백히 구분해야합니다.

 

┌추상 클래스 VS 인터페이스

추상 클래스는 상속을 받아 기능을 이용하거나 확장을 하기 위함이고 인터페이스는 구현의 강제에 목적을 두어 구현 객체의 같은 동작을 보장한다는 데에 있다.

뭣보다도 둘의 가장 큰 차이는 인터페이스의 장점인 다중 상속 유무다.

조금 더 깊게 파고 들어가면 추상 클래스는 상속의 개념이라 사용의도가 is-a 관계에 있지만 인터페이스는 의도가 다르게 can-do 관계에 있다.

이에 대한 자세한 설명은 아래에 ↓

유니티 C#에서 is-a관계? has-a 관계? 그리고 can-do 관계?

 

 


 

#2-1 인터페이스(Interface) 쓰는 법

 

인터페이스를 사용하기 위해 짚고 넘어갑시다

 

1. 선언은 interface라는 키워드로 선언해야합니다.

2. 어차피 공유해서 쓰기에 public으로 설정

3. 이름은 클래스와 구별되게 앞에 대문자 I 붙여줍니다.

public interface IDamageAble
{
    //* 요런 모양
}

 

4. 멤버로 메서드(함수), 인덱서, 프로퍼티(get, set), 이벤트(Event)같은 것들이 올 수 있습니다.

(C#이 업데이트하면 더 올 수 있을지도?)

public interface IDamageAble
{
    void TestFuntion(); //* 메서드(함수)
    int myInt {get;set;} //* 프로퍼티
    event EventHandler OnMyEvent; //* 이벤트
}

 

┏이외에 주의할점들 

5, 그냥 단순한 변수는 멤버로 사용 못하고 프로퍼티로 선언해야합니다.

6, 멤버들을 구현없이 선언만 가능합니다.

7, 선언한거 바꾸기 쉽지않습니다.

8, 그러니까 한번 선언할 때 제대로하는 습관을 들이도록합시다.

 


 

#2-2 인터페이스(Interface) 실전사용!

이제 기본적으로 어케 생겼는진 알겠으니 한번 실전 예제로 사용해봅시다.

위에서 인터페이스 설명하면서 건물이 아파하거나 부숴지는건 데미지 입는다는 함수를 공통적으로 가집니다.

그러면 이 상황에서 총알물리 충돌을 거치면서 데미지 입히는걸 인터페이스로 구현해봅시다.

 

1. 우선 인터페이스 스크립트 생성해서 구현합니다.

public interface IDamageAble
{
    void Damage();
}

작지만 큰 역할을 하는 데미지 입는 함수입니다.

그렇지만 저걸 크게 구현하는건 상속하는 자식들의 일입니다.

 

2.  이제 적과 건물이 상속하는걸 구현합시다.

public class Enemy : MonoBehaviour, IDamageAble
{
    public void Damage()
    {
        //* 대충 체력 체크
        //* 대충 피 흘리는 로직
        //* 대충 아파하는 모션
    }
}
public class Building : MonoBehaviour, IDamageAble
{
    public void Damage()
    {
        //* 대충 장애물 체력 체크
        //* 대충 건물 갈라지는 효과
        //* 대충 부숴지는 소리 바사사삿ㄱ
    }
}

보다시피 IDamageAble 인테페이스를 상속하면 무조건 public void Damage()으로 구현하게됩니다.

적과 건물의 안에 로직은 다르게 해도 됩니다.

 

3, 총알이 적과 건물에 데미지 입혀봅시다.

 

기존의 코드는 다음과 같습니다.

public class Bullet : MonoBehaviour{
    private void OnTriggerEnter2D(Collider2D collider) {
        Enemy enemy = collider.GetComponent<Enemy>();
        if(enemy != null)
            enemy.Damage();

        Building building = collider.GetComponent<Building>();
        if(building != null)
            building.Damage();
    }
}

보다보면 어지럽고 중복이 너무 많습니다.

만약에 건물만 있는게 아니라 나무, 동물, 아군 등등 데미지 입는 종류가 늘어나면 저 모든 스크립트를 다 참조하는건 너무 많은 노력과 시간이 들어가게됩니다.

 

이제 한번 인터페이스로 구현하면

public class Bullet : MonoBehaviour{
    private void OnTriggerEnter2D(Collider2D collider) {
        IDamageAble damageAble = collider.GetComponent<IDamageAble>();
        if(damageAble != null)
            damageAble.Damage();
    }
}

 

코드량이 적어진걸 볼 수 있습니다.

IDamageAble 인터페이스를 상속한 들이나 건물이면 인식이 되서 Damage() 함수를 호출하게 되는 방식입니다.


#3 인터페이스의 디폴트 인터페이스 멤버?

 

인터페이스는 구현이 안되지만 유니티 2019.2 버전 이상은 C# 7.3이니까 디폴트 인터페이스 멤버를 구현 가능해졌습니다.

이분 자료에선 C# 8.0부터 되는거같습니다.

 

디폴트 인터페이스 멤버란 말 그대로 기본적인 간단한 멤버 구현같은거를 뜻합니다

예를들어 if문이나 return문 같은거를 구현한 뒤 상속하는 자식이 따로 로직을 작성 하지 않으면 디폴트 인터페이스 멤버의 기본적인 간단한 구현 로직을 그대로 쓰게 됩니다.

원할 때 언제든지 따로 로직을 작성하면 되는겁니다.

근데 단점은 디폴트 인터페이스를 구현해놓고 그런 기능이 있었는지 기억 못하면 상속을 해도 에러가 안뜬다는 겁니다.

결론은 인터페이스 자체는 코드 정리하긴 좋은 기능이라는 생각이드니 여러분도 인터페이스를 사용해보시기 바랍니다.

COMMENT