C# 인터페이스 마스터하기: 견고한 객체 지향 설계를 위한 계약
인터페이스(Interface)는 인터페이스를 상속받는 모든 클래스가 따라야 하는 구문적 계약(Syntactical Contract)입니다. 인터페이스는 '무엇(What)'을 정의하고, 파생 클래스는 '어떻게(How)'를 구현합니다.
인터페이스는 속성(Properties), 메서드(Methods), 이벤트(Events)를 멤버로 가집니다. 인터페이스에는 멤버의 선언만 포함되며, 구현은 파생 클래스의 책임입니다. 파생 클래스들이 따라야 할 표준 구조를 제공합니다.
추상 클래스도 비슷한 목적을 가지지만, 기본 클래스에서 몇 개의 메서드만 선언하고 파생 클래스에서 기능을 구현할 때 주로 사용됩니다.
인터페이스 선언
interface 키워드로 선언하며, 클래스 선언과 유사합니다. 인터페이스 멤버는 기본적으로 public입니다.
public interface ITransactions
{
// 인터페이스 멤버 (구현 없음)
void ShowTransaction();
double GetAmount();
}
관례: 인터페이스 이름은 I 접두사로 시작 (예: IComparable, IDisposable)
인터페이스 구현 예제
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace InterfaceApplication
{
public interface ITransactions
{
void ShowTransaction();
double GetAmount();
}
public class Transaction : ITransactions
{
private string tCode;
private string date;
private double amount;
public Transaction()
{
tCode = " "; date = " "; amount = 0.0;
}
public Transaction(string c, string d, double a)
{
tCode = c; date = d; amount = a;
}
public double GetAmount() { return amount; }
public void ShowTransaction()
{
Console.WriteLine("Transaction: {0}", tCode);
Console.WriteLine("Date: {0}", date);
Console.WriteLine("Amount: {0}", GetAmount());
}
}
class Tester
{
static void Main(string[] args)
{
Transaction t1 = new Transaction("001", "8/10/2012", 78900.00);
Transaction t2 = new Transaction("002", "9/10/2012", 451900.00);
t1.ShowTransaction();
t2.ShowTransaction();
Console.ReadKey();
}
}
}
출력: Transaction: 001, Date: 8/10/2012, Amount: 78900 / Transaction: 002, Date: 9/10/2012, Amount: 451900
인터페이스 핵심 특징
- 인스턴스 생성 불가
- 멤버에 접근 지정자 사용 불가 (모두 public)
- 필드(인스턴스 변수) 선언 불가 (속성은 가능)
- 생성자/소멸자 정의 불가
- 클래스는 여러 인터페이스 구현 가능 (다중 구현)
- 인터페이스는 다른 인터페이스 상속 가능
- 구현 클래스에서
public으로 멤버 구현 필수
명시적 인터페이스 구현 (Explicit Interface Implementation)
같은 시그니처의 멤버를 여러 인터페이스가 가질 때, 또는 인터페이스 멤버를 클래스 외부에서만 노출하고 싶을 때 사용합니다.
interface I1 { void Method(); }
interface I2 { void Method(); }
class MyClass : I1, I2
{
// 명시적 구현: 인터페이스 이름으로 한정
void I1.Method() { Console.WriteLine("I1.Method"); }
void I2.Method() { Console.WriteLine("I2.Method"); }
// 암시적 구현 (공통)
public void Method() { Console.WriteLine("Public Method"); }
}
// 사용
MyClass obj = new MyClass();
obj.Method(); // Public Method
((I1)obj).Method(); // I1.Method
((I2)obj).Method(); // I2.Method
인터페이스의 속성, 이벤트, 인덱서
public interface IData
{
// 속성
string Name { get; set; }
int Count { get; } // 읽기 전용
// 이벤트
event EventHandler DataChanged;
// 인덱서
string this[int index] { get; set; }
}
기본 구현 메서드 (C# 8.0+)
C# 8.0부터 인터페이스에 메서드 기본 구현을 제공할 수 있습니다.
public interface ILogger
{
void Log(string message);
// 기본 구현
void LogError(string error)
{
Log($"ERROR: {error}");
}
}
인터페이스 vs 추상 클래스 비교
| 비교 항목 | 인터페이스 | 추상 클래스 |
| 다중 구현 | 가능 (여러 인터페이스 구현) | 불가능 (단일 상속만) |
| 구현 포함 | C# 8.0+ 기본 구현 가능 | 완전 구현 메서드 포함 가능 |
| 필드/상태 | 인스턴스 필드 불가 (정적 필드만) | 인스턴스 필드 가능 |
| 생성자 | 불가 | 가능 |
| 접근 지정자 | 모두 public | 모든 접근 지정자 가능 |
| 용도 | 계약 정의, 다형성, 플러그인 구조 | 공통 기반 구현 공유 |
설계 가이드: "무엇을 할 수 있는가"를 정의하면 인터페이스, "무엇인가"의 공통 기반을 제공하면 추상 클래스. 둘을 조합해 유연한 설계하세요.