명시적 인터페이스
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)을 깔끔하게 유지할 수 있습니다.
챌린지
쉬움명시적 인터페이스 구현(explicit interface implementation)을 통해 하나의 클래스가 사용되는 인터페이스에 따라 어떻게 서로 다른 동작을 제공할 수 있는지 보여주는 보고서 생성 시스템을 만들어 보겠습니다. 화면 표시용과 인쇄용으로 각각 다르게 형식이 지정되는 문서를 만들 것입니다.
코드는 다음 네 개의 파일로 구성됩니다:
IDisplayable.cs:Reports네임스페이스 안에IDisplayable이라는 인터페이스를 정의합니다. 이 인터페이스는 화면에 표시될 수 있는 콘텐츠를 나타냅니다. 문자열을 반환하는Render()메서드를 선언해야 합니다.IPrintable.cs:Reports네임스페이스 안에IPrintable이라는 인터페이스를 정의합니다. 이 인터페이스는 프린터로 전송될 수 있는 콘텐츠를 나타냅니다. 이 인터페이스 또한 문자열을 반환하는Render()메서드를 선언해야 합니다.IDisplayable과 메서드 이름이 충돌한다는 점에 유의하세요!Report.cs:Reports네임스페이스 안에IDisplayable과IPrintable을 모두 구현하는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 Report와 Q4 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:");
// 여기에 렌더링 결과 출력
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.