인터페이스(Interface)
클래스는 하나의 부모클래스만 상속할 수 있다.
즉, 여러 부모클래스로 부터 상속받을 수 있는 '다중 상속'을 할 수 없다.
인터페이스는 클래스가 다중상속을 할 수 없는 단점을 보완하기 위해 만들어진 개념이다.
즉, 클래스는 인터페이스를 여러 개 상속받을 수 있다.
인터페이스의 구조는 추상클래스와 비슷한데 공통점은 추상화를 사용한다는 것이다.
인터페이스는 다음과 같이 만든다.
- 인터페이스 선언은 interface 라는 키워드를 사용한다.
- 인터페이스 이름은 클래스명과 구별할 수 있도록 이름 앞에 대문자 I (아이)를 붙여 만든다.
- 메서드, 프라퍼티(property 속성), 인덱서(indexer) 등을 멤버로 가질 수 있다.
- 멤버는 모두 추상화만 가능하다. 즉, 멤버 선언만 할 수 있다.
- 추상 클래스와 마찬가지로 인스턴스(객체)를 생성할 수 없다.
이런 규칙으로 만든 인터페이스 예는 다음과 같다.
InterfaceExample.cs 스크립트 파일을 만든다.
InterfaceExample이라는 클래스를 만들고 MonoBehaviour을 상속한다.
11번줄, 17번줄에 ISword(검) , IShield(방패)라는 인터페이스를 만든다.
각각의 인터페이스에 추상 프라퍼티 StrikingPower(공격력), DefensivePower(방어력)과 추상 매서드 Attack(공격) , Defend(방어하다)를 선언한다.
13번,19번줄의 추상 프라퍼티 형태는 캡슐화에서 본 프라퍼티 형태와 조금 다르다.
이런 형태를 '자동 구현 프라퍼티' 라고 한다.
이것은 필드에 접근하기 위한 메서드를 구현하지 않고 단지 값을 가져오거나 저장하는 용도로만 사용할 때 쓴다.
인터페이스는 멤버의 추상 선언만 가능하므로 abstract 키워드는 생략한다.
또한 모든 멤버는 public으로 처리하므로 접근제한자도 생략한다.
이제 인터페이스의 추상 멤버를 구현(implement)해야 한다.
Knight(기사)라는 클래스를 만들고 인터페이스를 상속과 마찬가지로 콜론( : )을 사용해서 상속 받아서 구현해야 한다. 인터페이스가 여러 개 일때는 쉼표로 구분하여 적는다.
그리고 클래스의 실행 부분에 인터페이스의 멤버를 public으로 구현한다.
이제 Start메서드에서 다중 상속이 되는지 확인 해보자.
7번줄에 Knight클래스로 Tom이라는 객체를 만든다.
8번줄에 StrikingPower 멤버에 접근해서 90을 저장한다.
string타입이므로 90을 ToString( )메서드를 이용하여 타입 변환해야 한다.
ToString()메서드는 어떤 타입을 문자열(string) 타입으로 변환할 때 사용하는 메서드이다.
to string은 'string(문자열) 으로' 라는 뜻인데 to는 방향을 나타낸다.
9번줄에서 어떤 값이 저장되어 있는 지 출력한다.
10,11번줄에서 두 메서드도 호출 해본다.
스크립트를 저장한 후 유니티에서 실행하면 다음과 같은 결과가 나올것이다.
인터페이스가 다중 상속이 가능하다는 것을 확인했다.
그러면 인터페이스는 어떻게 사용하면 좋을가?
예를 하나 더 만들어 본다.
InterfaceTest라는 스크립트를 만든다.
IHero라는 인터페이스를 만든다.
추상 멤버는 Initialize(초기화 하다)라는 메서드,
health(건강)라는 프라퍼티(속성),
ApplyDamage(손상을 적용하다)라는 points(점수) 매개변수를 가지고 있는 메서드를 만든다.
InterfaceTest클래스에 인터페이스를 구현한다.
health 프라퍼티를 구현하고 Initialize메서드에서 health값에 100을 저장한다.
ApplyDamage메서드가 호출되면 points라는 매개변수로 값을 받아서 health값에서 뺀 후 저장하라고 구현했다.
Start메서드에 위와 같은 코드를 작성한다.
7번줄에서 gameObject의 컴퍼넌트로 인터페이스를 호출하여 IHero타입의 변수 test에 저장할 수 있다.
(인터페이스는 멤버에 접근하기 위한 객체를 만들 수 없다. )
이전 글에서 유니티에서 GetComponent 메서드는 다른 컴퍼넌트를 가져올 때 사용한다고 했다.
이때 컴퍼넌트의 타입(Type)을 제네릭 < > 기호에 넣으면 된다.
위와 같은 스크립트의 경우는 유니티의 base클래스인 MonoBehaviour 클래스를 상속받은 클래스를 gameObject(게임오브젝트)에 연결하면 컴퍼넌트로 사용할 수 있다. 그래서 객체를 만들 수 없는 IHero인터페이스도 호출할 수 있는 것이다.
8번줄에서 이 변수로 Initialize메서드를 호출한다.
9번줄에서 ApplyDamage메서드를 호출하여 인수로 20을 전달한다.
10번줄에서 health에 접근해서 10을 더한 후 그 값을 health에 다시 저장한다.
12번줄에서 health값이 어떻게 변했는 지 출력하여 확인한다.
스크립트를 저장한 후 실행하면 다음과 같이 될 것이다.
인터페이스는 여러 잇점이 있지만 핵심은 다형성(상속)이 가능할 뿐만 아니라 추상클래스의 한계를 넘어 다중 상속이 가능하므로 깊게 연결되지 않고 넓고 얕게 연결할 수 있다는 것이다.
이렇게 연결된 클래스들은 밀접한 관계가 아니기 때문에 프로젝트를 제작하다가 변경하거나 분리해야 할 때 복잡하고 심각한 에러를 일으킬 확률이 줄어들고 유연하게 대처할 수 있는 기회를 제공한다.
더 실제적인 예는 게임을 만들 때 확인하기로 한다.
끝.
Wraven...
'취미로 하는 게임코딩_gameCodingAsHobby > 유니티unity로 게임 만들기' 카테고리의 다른 글
유니티26_C#16_네임스페이스(NameSpace) (0) | 2021.03.12 |
---|---|
유니티25_C#15_구조체(Struct) (0) | 2021.03.09 |
유니티23_C#13_추상 클래스(Abstract class) (0) | 2021.03.06 |
유니티22_게임 제작 과정 06_Prefab 프리팹 만들기 (0) | 2021.03.02 |
유니티21_게임 제작 과정 05_충돌 설정 (0) | 2021.02.26 |