Menu
Coddy logo textTech

명시적 인터페이스

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

클래스가 이름이 같은 멤버를 포함하는 여러 인터페이스를 구현할 때, 이름 충돌이 발생합니다. 명시적 인터페이스 구현(Explicit interface implementation)은 각 인터페이스에 대해 별도의 구현을 제공할 수 있도록 하여 이 문제를 해결합니다.

명시적 구현을 사용하면, 멤버 이름 앞에 인터페이스 이름을 접두사로 붙이고 접근 제한자를 생략합니다:

public interface IAmericanPlug
{
    void Connect();
}

public interface IEuropeanPlug
{
    void Connect();
}

public class UniversalAdapter : IAmericanPlug, IEuropeanPlug
{
    void IAmericanPlug.Connect()
    {
        Console.WriteLine("Connected to 120V");
    }
    
    void IEuropeanPlug.Connect()
    {
        Console.WriteLine("Connected to 220V");
    }
}

명시적으로 구현된 멤버는 클래스 자체가 아니라 인터페이스 형식의 변수를 통해서만 액세스할 수 있습니다:

var adapter = new UniversalAdapter();
// adapter.Connect();  // 컴파일되지 않습니다!

IAmericanPlug american = adapter;
american.Connect();  // 120V에 연결됨

IEuropeanPlug european = adapter;
european.Connect();  // 220V에 연결됨

이 기술은 클래스의 공개 API에서 인터페이스 멤버를 숨기고자 할 때도 유용합니다. 메서드가 객체를 특정 인터페이스로 취급할 때만 의미가 있는 경우, 명시적 구현(explicit implementation)을 사용하면 계약을 충족하면서도 클래스의 노출 영역(surface area)을 깔끔하게 유지할 수 있습니다.

challenge icon

챌린지

쉬움

명시적 인터페이스 구현(explicit interface implementation)을 통해 하나의 클래스가 사용되는 인터페이스에 따라 어떻게 서로 다른 동작을 제공할 수 있는지 보여주는 보고서 생성 시스템을 만들어 보겠습니다. 화면 표시용과 인쇄용으로 각각 다르게 형식이 지정되는 문서를 만들 것입니다.

코드는 다음 네 개의 파일로 구성됩니다:

  • IDisplayable.cs: Reports 네임스페이스 안에 IDisplayable이라는 인터페이스를 정의합니다. 이 인터페이스는 화면에 표시될 수 있는 콘텐츠를 나타냅니다. 문자열을 반환하는 Render() 메서드를 선언해야 합니다.
  • IPrintable.cs: Reports 네임스페이스 안에 IPrintable이라는 인터페이스를 정의합니다. 이 인터페이스는 프린터로 전송될 수 있는 콘텐츠를 나타냅니다. 이 인터페이스 또한 문자열을 반환하는 Render() 메서드를 선언해야 합니다. IDisplayable과 메서드 이름이 충돌한다는 점에 유의하세요!
  • Report.cs: Reports 네임스페이스 안에 IDisplayableIPrintable을 모두 구현하는 Report 클래스를 정의합니다. 보고서는 Title 속성(string)과 Content 속(string)을 가져야 하며, 두 값을 모두 설정하는 생성자가 있어야 합니다. 명시적 인터페이스 구현을 사용하여 서로 다른 Render() 동작을 제공하세요:
    • 화면 표시용으로 렌더링될 때: "[SCREEN] {Title}: {Content}"
    • 인쇄용으로 렌더링될 때: "[PRINT] {Title} | {Content}"
  • Program.cs: 메인 파일에서 입력값을 사용하여 Report 객체를 생성합니다. 명시적 구현은 인터페이스 변수를 통해서만 접근할 수 있으므로, 동일한 보고서 객체를 IDisplayable 변수와 IPrintable 변수에 각각 저장하세요. 그런 다음 각 변수에서 Render()를 호출하여 동일한 객체가 사용하는 인터페이스에 따라 어떻게 다른 출력을 생성하는지 확인합니다.

두 개의 입력을 받게 됩니다:

  • 보고서 제목 (Report title)
  • 보고서 내용 (Report content)

출력은 다음 형식으로 인쇄하세요:

Display version:
{Render() via IDisplayable}
Print version:
{Render() via IPrintable}

예를 들어, 입력값이 Sales ReportQ4 revenue increased by 15%라면, 출력은 다음과 같아야 합니다:

Display version:
[SCREEN] Sales Report: Q4 revenue increased by 15%
Print version:
[PRINT] Sales Report | Q4 revenue increased by 15%

동일한 Report 객체가 접근하는 인터페이스 참조에 따라 어떻게 다르게 동작하는지 확인해 보세요. 이것이 바로 이름 충돌을 해결하면서 상황에 적합한 동작을 제공하는 명시적 인터페이스 구현의 힘입니다!

직접 해보기

using System;
using Reports;

class Program
{
    public static void Main(string[] args)
    {
        // 입력 읽기
        string title = Console.ReadLine();
        string content = Console.ReadLine();

        // TODO: title과 content를 사용하여 Report 객체 생성

        // TODO: 리포트를 IDisplayable 변수에 저장

        // TODO: 동일한 리포트를 IPrintable 변수에 저장

        // TODO: IDisplayable의 Render()를 호출하여 디스플레이 버전 출력
        Console.WriteLine("Display version:");
        // 여기에 렌더링 결과 출력

        // TODO: IPrintable의 Render()를 호출하여 프린트 버전 출력
        Console.WriteLine("Print version:");
        // 여기에 렌더링 결과 출력
    }
}
quiz icon실력 점검

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

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