2022. 3. 22. 12:53ㆍLanguages/C#
/* <이것이 C#이다> 책을 바탕으로 공부한 글입니다. */
다중상속이 허용되지 않는 C#에서 인터페이스(Interface)는 객체지향 프로그래밍을 한층 더 강력하게 만들어주는 요소다. 객체지향의 꽃이며, 객체지향 프로그래밍의 고수는 인터페이스를 잘 활용할 수 있어야 한다고 한다.
인터페이스(Interface)의 선언과 특징
인터페이스는 다음과 같은 선언 형식과 특징을 가진다.
interface 인터페이스이름
{
반환형 메소드이름1(매개변수 목록);
반환형 메소드이름2(매개변수 목록);
...
}
- 인터페이스는 메소드, 이벤트, 인덱서, 프로퍼티만 가질 수 있다.
- 접근 제한 한정자를 사용할 수 없고, 모든 것이 public으로 선언된다.
- 인터페이스는 자신을 상속받는 클래스에게 오버라이딩을 강제한다.
- 자식 클래스에서 구현할 메소드들은 public 한정자로 수식해야 한다.
- 구현부가 없다.
- 인스턴스를 만들 수 없지만, 인터페이스를 상속받는 클래스의 인스턴스를 만드는 것은 가능하다.
- 클래스는 인터페이스를 여러 개 상속 받는 것이 가능하다.
인터페이스는 상호간의 약속이다.
PC에 USB 포트가 존재해 USB 플래시 메모리를 꽂아 저장 장치로 쓸 수도 있고, 키보드나 마우스를 꽂으면 입력 장치로도 사용할 수 있다. 또한, USB 선풍기를 꽂으면 선풍기로 쓸 수 있기도 하다. 이렇게 USB 포트가 다양하게 활용될 수 있는 이유는 PC와 다른 주변기기(USB 메모리, 키보드, 마우스, USB 선풍기)들이 USB라는 약속을 따르기 때문이다.
마찬가지로 인터페이스도 소프트웨어 내에서 USB와 같은 역할을 한다. 상속받는 클래스가 따라야할 약속을 정의하는 셈이다.
interface ILogger // C#에서는 인터페이스명 첫 글자에 'I'를 붙이는 것이 암묵적인 룰이다.
{
void WriteLog(string message);
}
위 인터페이스를 상속받아 구현한 ConsoleLogger 클래스이다. ConsoleLogger 클래스는 WriteLog(string message) 메소드를 강제로 구현해야 한다.
class ConsoleLogger : ILogger
{
public void WriteLog(string message)
{
Console.WriteLine("{0} {1}", DateTime.Now.ToLocalTime(), message);
}
}
인터페이스 인스턴스는 생성하지 못하지만, 참조는 만들 수 있다.
ILogger logger = new ConsoleLogger();
logger.WriteLog("Hello, World!");
위 코드에서는 로그를 출력하도록 ILogger 인터페이스를 상속 받아, ConsoleLogger 클래스를 만들었다. 그 외에도 ILogger 인터페이스를 상속 받는 새로운 클래스를 만들어서 로그를 파일에 저장하거나, 서버에 저장하도록 패킷을 보낼수도 있을 것이다.
실전 예시
사용자로부터 온도를 반복적으로 입력받아 기록하는 ClimateMonitor 클래스를 만들어본다. 로그를 저장하는 방식은 ClimateMonitor 클래스를 사용하는 다른 프로그래머들의 입맛에 따라 결정할 수 있다. 이럴 때, 인터페이스는 빛을 발하게 된다.
class ClimateMonitor
{
private ILogger logger;
public ClimateMonitor(ILogger logger)
{
this.logger = logger;
}
public void Start()
{
while(true)
{
Console.Write("온도를 입력해주세요 : ");
string temperature = Console.ReadLine();
if(temperature == "")
break;
logger.WriteLog("현재 온도 : " + temperature);
}
}
}
아까 만들었던 ConsoleLogger 클래스를 인자로 넘기게 되면, 모니터는 로그를 출력하는 기능을 한다.
ClimateMonitor monitor = new ClimateMonitor(new ConsoleLogger());
monitor.Start();
이번엔 텍스트 파일에 로그를 출력하는 FileLogger 클래스를 만들어보자.
using System.IO;
class FileLogger : ILogger
{
private StreamWriter writer;
public FileLogger(string path)
{
writer = File.CreateText(path);
writer.AutoFlush = true;
}
public void WriteLog(string message)
{
writer.WriteLine("{0} {1}", DateTime.Now.ToShortTimeString(), message);
}
}
그리고 모니터에 인자로 전달해보자.
ClimateMonitor monitor = new ClimateMonitor(new FileLogger("MyLog.txt"));
monitor.Start();
즉, ConsoleLogger, FileLogger는 "ILogger"라는 사전에 약속한 인터페이스를 지켜서 만들었고, ClimateMonitor는 해당 인스턴스의 참조를 받아 실행만 하면 서로 다른 기능을 하지만 호환이 되는 신기한 현상이 벌어진다.
ClimateMonitor에게 ConsoleLogger 객체를 주면, ClimateMonitor는 콘솔에 로그를 출력하는 기능을 한다.
ClimateMonitor에게 FileLogger 객체를 주면, ClimateMonitor는 텍스트 파일에 로그를 출력하는 기능을 한다.
마치 위에서 PC와 서로 다른 주변기기들을 USB로 연결했는데 호환이 가능하면서 제 각각 다른 기능을 하는 것과 똑같지 않은가? 이것이 인터페이스의 강력함이다.
'Languages > C#' 카테고리의 다른 글
[C#] 인터페이스와 클래스의 사이 : 추상 클래스(Abstract Class) (0) | 2022.03.23 |
---|---|
[C#] 객체지향의 꽃, 인터페이스(Interface) - 2편 (0) | 2022.03.22 |
[C#] 여러 필드를 담을 수 있는 구조체, 튜플(Tuple) (0) | 2022.03.21 |
[C#] 구조체(Structure)에 대해 알아보자! (0) | 2022.03.21 |
[C#] 확장 메소드 (Extension Method) (0) | 2022.03.21 |