C# 인터페이스와 추상클래스의 차이점
Interface | Abstract Class | |
접근 지정자 | - 함수에 대한 접근 지정자를 가질수 없습니다. - public 만 사용가능 |
- 함수에 대한 접근 지정자를 가질 수 있습니다. |
구현 | 구현이 아닌 선언만 가짐 | 구현도 가질 수 있음 |
속도 | 상대적으로 느림 | 빠름 |
인스턴스화 | 불가 | 불가 |
필드 | 상수만 가능, 프로퍼티 선언 가능 | 정의할 수 있음, 프로퍼티 선언, 구현 가능(자동구현되긴함) |
메소드 | 추상메소드만 가짐(즉, 다 구현해야함) | 비추상 메소드도 가질 수 있음 |
상속 | 하나 이상 가능 | 하나만 됨 |
생성자 | 선언 불가 | 선언 가능 |
역할 | 다양한 클래스에서 동일한 메소드명을 공유, 클래스 간 일관성 있는 동작을 보장하기 위한 계약 역할 |
동일한 종류의 클래스들이 공유하는 기본 구현을 제공 |
사용 경우 | 다양한 클래스들이 특정 메소드나 동작을 구현하도록 강제하려는 경우 | 다양한 클래스들이 공통된 기능이나 동작을 가지고 있고, 이러한 기능을 기본적으로 구현하면서도 하위 클래스에서 확장 및 수정이 필요한 경우 |
abstract 메소드가 있으면 클래스도 abstract 키워드 달아줘야함
abstract클래스에서 프로퍼티는 아래와 같이 선언까지만 가능. 구현은 상속받은 자식 클래스에서 가능
c#에서 프로퍼티는 메소드로 구현됨
public abstract class Parent : MonoBehaviour
{
public abstract int TestProperty
{
// Notice the accessor accessibility level.
protected set;
// No access modifier is used here.
get;
}
}
public class child : Parent
{
public override int TestProperty
{ get => throw new System.NotImplementedException();
protected set => throw new System.NotImplementedException();
}
}
- virtual : 하나의 기능을 하는 완전한 클래스이며, 파생클래스에서 상속해서 추가적인 기능추가 및 virtual 한정자가 달린 것을 재정의해서 사용 가능. 재정의 필수X
- abstract : 여러 개의 파생클래스에서 공유할 기본클래스의 공통적인 정의만 하고, 파생클래스에서 abstract한정자가 달린 모든 것을 재정의해야함. 재정의 필수O
- interface : abstract와 비슷하나 멤버변수를 사용할 수 없음. static 상수는 가능.
abstract는 주로 계층적인 상속( Dog : Animal ,,, Cat : Animal)구조에서 사용되며
interface는 주로 서로 다른 계층 ( Speaker : ISpeak ,,, Npc : ISpeak기능을 추가하려고 할 때 사용.
프로퍼티 관련
- abstract: Never an auto-property but looks like an auto-property.
- virtual: Can be an auto-property.
- override: Can be an auto-property.
< interface 사용 이유 중 하나 >
플레이어가 논타겟으로 공격했을 때 범위 안의 모든 공격 가능한 오브젝트에게 피해를 준다고 하자. 이 경우 대부분 몬스터가 해당하겠지만, 공격 가능한 오브젝트 등도 해당될 수 있다. 이때 간단하게는 다음과 같이 코드를 작성할 수 있다.
private void OnCollisionEnter(Collision collision)
{
if (CompareTag("Attackable"))
{
collision.gameObject.GetComponent<Status>().hp -= damage;
}
}
하지만, Tag를 위와 같이 너무 큰 범위로 묶는 것은 효율적이지 못하다. 그렇다고 태그별로 조건문을 일일이 달아줄 수도 없는 노릇이다. 이럴 때 인터페이스를 활용하면 다음과 같이 코드를 바꿀 수 있다.
private void OnCollisionEnter(Collision collision)
{
Attackable attackable = collision.gameObject.GetComponent<Attackable>();
if (attackable != null)
{
attackable.Damaged();
}
}
인터페이스를 상속하면 컴포넌트로써 읽는 것이 가능해지고, 다중 상속이 가능한 덕분에 어떤 클래스에라도 Attackable 인터페이스를 상속하여 공격 가능한 오브젝트임을 표현할 수 있다.
'C#' 카테고리의 다른 글
구조체 메모리 할당 시, 변수 타입의 순서에 주의하기! ( 작은 자료형부터 쓰기 ) (0) | 2023.10.17 |
---|---|
C# 문법 _ 델리게이트(delegate), 람다식, 제네릭 (0) | 2023.10.16 |