인터페이스와 추상클래스
C#에서 인터페이스란 무엇일까?
추상화를 통해 다양한 클래스가 동일한 동작을공유하도록 하는 개념을 Interface라 한다. 이 인터페이스는 메서드, 속성, 이벤트 및 인덱서가 정의 가능한데, 구현할때 멤버들을 반드시 구현해야한다.
인터페이스는 클래스간의 결합도를 낮추고 유연한 설계를 할수있게 해준다. 실무에서 보통 대게 인터페이스 이름 앞에 'I'를 붙여준다.
다음은 온도를 통한 예제이다.
using System;
using System.IO;
namespace Interface
{
interface ILogger
{
void WriteLog(string message);
}
class ConsoleLogger : ILogger
{
public void WriteLog(string message)
{
Console.WriteLine("{0},{1}", DateTime.Now.ToLocalTime(),message);
}
}
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);
}
}
class ClimateMonitor
{
private ILogger logger;
public ClimateMonitor(ILogger logger)
{
this.logger = logger;
}
public void start()
{
while (true)
{
Console.WriteLine("온도를 입력해주세요 : ");
string temperature = Console.ReadLine();
if (temperature == "")
break;
logger.WriteLog("현재 온도 : " + temperature);
}
}
}
class Program
{
static void Main(string[] args)
{
ClimateMonitor monitor = new ClimateMonitor(new FileLogger("MyLog.txt")); //monitor 객체는 어플리케이션이 시작된 디렉터리에 MyLog.txt를 만들고 여기에 로그를 남깁니다.
monitor.start();
}
}
}
//
실행결과
온도를 입력해주세요 : 22
온도를 입력해주세요 : 30
온도를 입력해주세요 : 26
MyLog.txt내용
오후 11:31 현재 온도 : 22
오후 11:31 현재 온도 : 30
오후 11:31 현재 온도 : 26
인터페이스를 상속하는 인터페이스
인터페이스 위에 인터페이스를... 얹어드시겠습니까? Interface위에 새로운 Interface를 상속해봅시다.
using System;
namespace DerivedInterface
{
interface ILogger
{
void WriteLog(string message);
}
interface IFormattableLogger : ILogger
{
void WriteLog(string format, params Object[] args);
//IFormattableLogger는
//Void WriteLog와 Void WriteLog(string format, params Object[] args) 메소드 두 개를 가지게된다.
}
class ConsoleLogger2 : IFormattableLogger
{
public void WriteLog(string message)
{
Console.WriteLine("{0} {1}", DateTime.Now.ToLocalTime(),message);
}
public void WriteLog(string format, params object[] args)
{
String message = String.Format(format, args);
Console.WriteLine("{0} {1}", DateTime.Now.ToLocalTime(), message);
}
}
class Program
{
static void Main(string[] args)
{
IFormattableLogger logger = new ConsoleLogger2();
logger.WriteLog("The world is not flat.");
logger.WriteLog("{0} + {1} = {2}", 1, 1, 2);
}
}
}
실행결과
2023-08-24 오후 11:42:02 The world is not flat.
2023-08-24 오후 11:42:02 1 + 1 = 2
인터페이스 한꺼번에 상속하는 법
인터페이스는 일단 한꺼번에 상속시키지 않는다. '죽음의 다이아몬드'라는 문제때문. 무엇을 출력할지 모르기때문에, C#은 다중 상속을 허용하지 않는다.
인터페이스 기본구현 메서드
인터페이스에 새로운 메서드를 추가했는데, 오버라이딩 안할시 출력되는 것.
using System;
namespace ConsoleApp10
{
interface ILogger
{
void WriteLog(string message);
void WriteError(string error) //새 메서드 추가
{
WriteLog($"Error: {error}");
}
}
class ConsoleLogger : ILogger
{
public void WriteLog(string message)
{
Console.WriteLine($"{DateTime.Now.ToLocalTime()}, {message}");
}
}
class Program
{
static void Main(string[] args)
{
ILogger logger = new ConsoleLogger();
logger.WriteLog("System Up~!");
logger.WriteError("System Fail...");
ConsoleLogger clogger = new ConsoleLogger();
clogger.WriteLog("System Up~?"); //Ok
}
}
}
실행결과
2023-08-24 오후 11:58:21, System Up~!
2023-08-24 오후 11:58:21, Error: System Fail...
2023-08-24 오후 11:58:21, System Up~!
추상클래스(abstract)
추상클래스는 '구현'을 가질수있다. 하지만 클래스와 달리 인스턴스는 가질 수 없다. 접근성을 이야기해보자면 인터페이스에 모든 메소드는 public이지만, 클래스는 한정자를 명시하지 않으면 모든 메소드가 private로 선언된다..
추상 클래스는 클래스와 다른점이 추상 메소드(Abstract Method)를 가질 수 있다. 이 추상 메소드는 추상 클래스가 인터페이스의 역할도 할 수 있게 해주는 장치다. '구현'은 못 가지지만, 파생클래스에서 반드시 갖도록 강제를 하기에... 그렇다면 이 메서드의 접근성은 어떨까? 이 메서드들은 기본이 private인 추상 클래스와 다르게 메서드는 public, protected, internal, protected internal 한정자 중 하나로 수식될 것을 C# 컴파일러가 강요한다.
다음 예제를 보자.
using System;
namespace ConsoleApp10
{
abstract class AbstractBase
{
protected void PrivateMethodA() => Console.WriteLine("AbstractBase.PrivateMethodA()");
public void PublicMethodA() => Console.WriteLine("AbstractBase.PublicMethodA()");
public abstract void AbstractMethodA();
}
class Derived : AbstractBase
{
public override void AbstractMethodA()
{
Console.WriteLine("Derived.AbstractMethodA()");
PrivateMethodA();
}
}
class Program
{
static void Main(string[] args)
{
AbstractBase obj = new Derived();
obj.AbstractMethodA();
obj.PublicMethodA();
}
}
}
실행결과
Derived.AbstractMethodA()
AbstractBase.PrivateMethodA()
AbstractBase.PublicMethodA()
Derived.AbstractMethodA()
Dervied 클래스는 AbstractBase 클래스를 상속 받고, AbstractMethodA() 를 Dervied 클래스에 구현중이므로
obj.AbstractMethodA() 를 실행시 Derived.AbstractMethodA()가 출력된다.
AbstractBase.PrivateMethodA()
PrivateMethodA()를 출력하고싶어도 (private) abstract class AbstractBase 이므로 못하지만,
Dervied 클래스 내부에서는 PrivateMethodA()이 접근 가능하므로 AbstractBase.PrivateMethodA()가 출력된다.
AbstractBase.PublicMethodA()
AbstractBase 클래스의 PublicMethodA()는 public이므로.
추상클래스는 일반 클래스가 가질 수 있는 구현과 더불어 추상메소드를 가질수있다. 한마디로 추상 클래스의 인스턴스를 다루는 것과 코드의 중복을 피하고 유지 보수성을 향상시키는 기능 덕분에 프로그램의 유연성과 확장성이 높인다..라나 뭐라나..
'C#.' 카테고리의 다른 글
| 이것이 C#이다 9장 ) 인터페이스와 추상클래스의 프로퍼티 (feat:무명형식) (0) | 2023.08.31 |
|---|---|
| 이것이 C#이다 9장) 불변 객체 record (0) | 2023.08.30 |
| 이것이 C#이다 9장) 자동구현 Property (0) | 2023.08.30 |
| 이것이 C#이다 7장) 클래스와 객체, 인스턴스의 차이 (0) | 2023.08.23 |
| 이것이 C#이다 7장) 형식 반환과 오버라이딩 (0) | 2023.08.22 |