추상 클래스 vs 인터페이스 (Interfaces vs Abstract Classes)
C#에서 추상화를 달성하는 두 가지 주요 방법은 추상 클래스 와 인터페이스 입니다. 두 방식 모두 디자인 패턴과 원칙을 구현하는 데 유효하지만, 상황에 따라 적절한 선택이 필요합니다. 소스에서는 기본적으로 "상속보다는 구성(Composition over inheritance)" 을 선호하는 방향을 제시하고 있습니다.
1. 추상 클래스 (Abstract Classes)
추상 클래스는 abstract 키워드를 사용하여 정의하며, 하위 클래스에 공통적인 기능을 전달하는 기반 클래스 역할을 합니다.
- "is a" 관계: 상속은 객체 간의 "is a(일종의 ~이다)" 관계를 정의합니다. (예: 자동차는 일종의 탈것이다.)
- 코드 공유: 필드, 상수, 정적 멤버뿐만 아니라 로직이 구현된 메서드를 가질 수 있어 구체적인 클래스 간에 핵심 기능을 공유할 수 있습니다.
- 제한적 접근:
protected,private등 다양한 접근 제한자를 사용할 수 있습니다. - 단일 상속의 한계: C#에서 클래스는 단 하나의 기반 클래스만 상속받을 수 있습니다. 이는 클래스가 여러 기반 클래스의 특성을 동시에 가져야 할 때 결정을 어렵게 만듭니다.
2. 인터페이스 (Interfaces)
인터페이스는 상속 패러다임에 깔끔하게 들어맞지 않는 기능에 대해 더 큰 유연성을 제공합니다.
- "has a" 관계: 인터페이스는 객체가 가진 "has a(능력을 갖춘)" 관계를 정의하며, 주변적인 능력을 추가할 때 유용합니다.
- 선언만 포함: 인터페이스는 멤버의 선언만 포함하며, 실제 로직은 이를 구현하는 클래스에서 담당해야 합니다.
- 다중 구현: 하나의 클래스가 여러 개의 인터페이스를 동시에 구현할 수 있어 확장성이 뛰어납니다.
3. 주요 차이점 요약
소스에서 제공하는 두 개념의 기술적 차이점은 다음과 같습니다:
| 기능 | 추상 클래스 | 인터페이스 |
|---|---|---|
| 메서드 구현 | 완전 또는 부분 구현 가능 | 선언만 가능 (구현 불가) |
| 변수 및 필드 | 선언 및 사용 가능 | 사용 불가 (메서드와 프로퍼티만 가능) |
| 정적 멤버 | 가질 수 있음 | 선언/사용 불가 |
| 생성자 | 사용함 | 사용 불가 |
| 접근 제한자 | 모든 제한자 사용 가능 (protected 등) | 사용 불가 (모든 멤버는 암시적으로 public) |
4. 선택 가이드: 무엇을 사용해야 할까?
소스는 이 결정을 항상 "이것 아니면 저것"의 문제로 보지 말라고 조언합니다.
- 추상 클래스 사용 시기: 코드를 공유하고 싶은 **기본 기능(Base functionality)**을 정의할 때 사용하십시오.
- 인터페이스 사용 시기: 유연성이 필요한 **주변 기능(Peripheral abilities)**을 정의할 때 사용하십시오.
Unity 예시:
로봇 NPC를 만든다면, 로봇의 핵심 기능을 담은 Robot 추상 클래스를 상속받고(is a), 전원을 끄고 켤 수 있는 기능을 ISwitchable 인터페이스로 구현(has a)하여 조합할 수 있습니다.
결론: SOLID 원칙을 이해하는 것과 마찬가지로, 이 두 개념을 적재적소에 활용하는 것은 매일 코딩하며 익혀야 하는 연습의 문제입니다. 핵심은 추상화에 의존 하여 클래스 간의 결합도를 낮추는 것입니다.
