Menu
Coddy logo textTech

인터페이스 vs 추상 클래스

Coddy C# 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 70개 중 26번째.

Both interface와 abstract class는 다른 class가 따라야 하는 계약을 정의할 수 있지만, 서로 다른 목적을 가지고 있으며 기능도 서로 다릅니다.

interface는 구현 없이 class가 무엇을 해야 하는지 정의합니다. 이는 순수한 계약입니다:

public interface IFlyable
{
    void Fly();
}

public class Bird : IFlyable
{
    public void Fly()
    {
        Console.WriteLine("Flapping wings");
    }
}

abstract class는 계약과 공유 구현을 모두 제공할 수 있습니다. 이는 부분적인 청사진입니다:

public abstract class Vehicle
{
    public string Brand { get; set; }
    
    public void StartEngine()
    {
        Console.WriteLine("Engine started");
    }
    
    public abstract void Drive();  // 반드시 구현해야 함
}

public class Car : Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Driving on roads");
    }
}

주요 차이점은 상속 규칙과 목적에 있습니다.

class는 여러 interface를 구현할 수 있지만 하나의 abstract class에서만 상속할 수 있습니다.

서로 관련이 없는 클래스가 동작을 공유해야 할 때 인터페이스를 사용하세요(예: 새와 비행기를 위한 IFlyable). 관련된 클래스가 공통 코드와 상태를 공유할 때는 추상 클래스를 사용하세요(예: 차량이 엔진 시동 메커니즘을 공유하는 경우).

abstract class는 생성자, 필드 및 멤버의 접근 제한자를 가질 수 있습니다. 인터페이스에는 전통적으로 이러한 기능이 없었지만, 최신 C#에서는 기본 구현을 허용합니다.

확신이 서지 않을 때는 유연성을 위해 인터페이스를 우선하세요. 공유 구현이 필요해지면 나중에 언제든지 abstract 클래스를 추가할 수 있습니다.

challenge icon

챌린지

쉬움

인터페이스와 abstract class 중 언제 무엇을 사용해야 하는지 보여 주는 미디어 플레이어 시스템을 만들어 보겠습니다. 서로 관련 없는 장치들이 인터페이스를 통해 재생 동작을 공유하고, 서로 관련된 미디어 유형들이 abstract class를 통해 공통 구현을 공유하도록 설계합니다.

코드를 네 개의 파일로 구성합니다:

  • IPlayable.cs: Media namespace에 IPlayable이라는 interface를 Define합니다. 이 interface는 휴대폰, TV 또는 전용 음악 플레이어처럼 미디어를 재생할 수 있는 모든 대상이 따라야 하는 계약을 나타냅니다. 문자열을 반환하는 단일 method Play()을 declare해야 합니다.
  • MediaFile.cs: Media namespace에 MediaFile이라는 abstract class를 Define합니다. 이는 모든 미디어 파일을 위한 공통 기반을 나타냅니다. Title property(string)와 Duration property(int, 초를 나타냄)를 가져야 합니다. 두 값을 설정하는 constructor를 포함합니다. "{Title} ({Duration}s)"를 반환하는 concrete method GetInfo()를 추가합니다. 또한 문자열을 반환하는 abstract method GetType()을 declare합니다. 각 미디어 유형이 어떤 종류의 파일인지 Define하게 됩니다.
  • AudioFile.cs: Media namespace에 AudioFile class를 Define하고, MediaFile을 Inherits하며 IPlayable을 Implements하도록 합니다. Artist property(string)를 추가합니다. constructor는 title, duration, artist를 받아야 합니다. GetType()을 override하여 "Audio"를 반환하도록 합니다. Play()를 Implement하여 "Playing audio: {Title} by {Artist}"를 반환하도록 합니다.
  • Program.cs: main 파일에서 input 값을 사용해 AudioFile을 Create합니다. class의 두 측면을 모두 보여 줍니다. abstract class에서 Inherits한 GetInfo()GetType()을 호출한 다음, interface에서 제공하는 Play()를 호출합니다. audio file을 IPlayable variable에 저장하고 Play()를 다시 호출하여 interface 다형성을 보여 줍니다.

세 개의 input을 받습니다:

  • 노래 제목
  • 초 단위의 재생 시간
  • Artist 이름

다음 형식으로 출력을 출력합니다:

Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}

예를 들어 input이 Bohemian Rhapsody, 354, Queen이라면 출력은 다음과 같아야 합니다:

Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by Queen

AudioFile이 두 접근 방식의 이점을 모두 얻는 방식을 확인하세요. abstract class에서 공통 구현(GetInfo())을 Inherits하는 동시에 IPlayable 계약도 충족합니다. abstract class는 관련된 미디어 유형에 코드 재사용을 제공하는 반면, interface를 사용하면 상속 계층 구조를 공유하지 않는 어떤 관련 없는 class도 "playable"이 될 수 있습니다.

직접 해보기

using System;
using Media;

class Program
{
    public static void Main(string[] args)
    {
        // 입력 값 읽기
        string title = Console.ReadLine();
        int duration = Convert.ToInt32(Console.ReadLine());
        string artist = Console.ReadLine();
        
        // TODO: 입력 값을 사용하여 AudioFile 생성
        
        // TODO: Info: 뒤에 GetInfo()의 결과 출력
        
        // TODO: Type: 뒤에 GetType()의 결과 출력
        
        // TODO: Direct: 뒤에 Play()의 결과 출력
        
        // TODO: 오디오 파일을 IPlayable 변수에 저장
        
        // TODO: Via Interface: 뒤에 IPlayable 변수의 Play() 결과 출력
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C# 컴파일러