C# 인터페이스와 추상 클래스

김민구·2025년 5월 27일
0

C#

목록 보기
18/31

인터페이스란 (Interface)

인터페이스는 일종의 약속입니다. 인터페이스를 선언하면 해당 인터페이스를 구현하는 클래스는 인터페이스에 정의된 모든 멤버(메서드, 속성 등)를 반드시 구현해야 하는 계약을 맺게 됩니다.

  • 인터페이스의 선언
    인터페이스는 interface 키워드를 사용하여 선언합니다.

    interface 인터페이스_이름
    {
        반환_형식 메서드_이름1(매개변수_목록);
        반환_형식 메서드_이름2(매개변수_목록);
        // ...
    }

    예를 들어, 로깅 기능을 위한 ILogger 인터페이스는 다음과 같이 선언할 수 있습니다:

    interface ILogger
    {
        void WriteLog(string message);
    }

    C# 프로그래머들 사이에서는 인터페이스 이름 앞에 대문자 'I'를 붙이는 것이 일반적인 관례입니다.

  • 인터페이스 구현
    어떤 클래스가 특정 인터페이스를 구현하려면 클래스 이름 뒤에 콜론 :을 붙이고 구현할 인터페이스 이름을 나열합니다. 인터페이스를 구현하는 클래스는 인터페이스에 정의된 모든 멤버를 public으로 구현해야 합니다.

    class ConsoleLogger : ILogger
    {
        public void WriteLog(string message)
        {
            // 콘솔에 메시지를 출력하는 구현
            Console.WriteLine("{0} {1}", DateTime.Now.ToLocalTime(), message);
        }
    }

    ConsoleLogger 클래스는 ILogger 인터페이스를 구현하여 WriteLog(string message) 메서드를 제공합니다. 마찬가지로 파일에 로깅하는 FileLogger 클래스도 ILogger 인터페이스를 구현할 수 있습니다.

  • 인터페이스의 활용
    인터페이스를 사용하면 코드의 유연성과 확장성을 높일 수 있습니다. 특정 인터페이스를 매개변수로 받거나 변수 타입으로 사용하면, 해당 인터페이스를 구현하는 어떤 클래스의 객체든 사용할 수 있습니다.
    예를 들어, 온도를 모니터링하는 ClimateMonitor 클래스가 로깅 기능을 사용해야 할 때, 특정 로거 클래스(ConsoleLoggerFileLogger)에 의존하는 대신 ILogger 인터페이스에 의존하도록 설계할 수 있습니다.

    class ClimateMonitor
    {
        private ILogger logger; // ILogger 타입의 변수
    
        public ClimateMonitor(ILogger logger) // 생성자에서 ILogger 객체를 받음
        {
            this.logger = logger;
        }
    
        public void start()
        {
            // ... 모니터링 코드 ...
            logger.WriteLog($"현재 온도 : {temperature}"); // ILogger 인터페이스를 통해 로깅
        }
    }

    이렇게 하면 ClimateMonitor를 사용할 때 콘솔 로거(new ClimateMonitor(new ConsoleLogger());)를 사용하든, 파일 로거(new ClimateMonitor(new FileLogger("myLog.txt"));)를 사용하든 코드를 변경할 필요 없이 로깅 구현체만 갈아끼울 수 있습니다.

  • 인터페이스 상속
    인터페이스는 다른 인터페이스를 상속받을 수 있습니다. 자식 인터페이스는 부모 인터페이스의 멤버를 모두 포함하며, 추가적인 멤버를 정의할 수 있습니다.

    interface IFormattableLogger : ILogger // ILogger를 상속받음
    {
        void WriteLog(string format, params Object[] args); // 추가 메서드 선언
    }

    IFormattableLogger 인터페이스를 구현하는 클래스는 ILoggerWriteLog(string message)IFormattableLoggerWriteLog(string format, params Object[] args) 메서드를 모두 구현해야 합니다.

  • 다중 인터페이스 구현
    C# 클래스는 여러 개의 인터페이스를 동시에 구현할 수 있습니다. 이는 클래스가 여러 인터페이스의 '계약'을 모두 이행하겠다고 약속하는 것입니다. C#은 클래스의 다중 상속은 허용하지 않지만, 인터페이스의 다중 구현을 통해 다중 상속과 유사한 효과를 얻을 수 있습니다.
    예를 들어, 달릴 수도 있고 날 수도 있는 FlyingCar 클래스는 IRunnableIFlyable 인터페이스를 동시에 구현할 수 있습니다.

  • 인터페이스 기본 구현 메서드
    C# 8.0부터 인터페이스에 기본 구현을 가진 메서드를 정의할 수 있게 되었습니다. 이를 통해 기존 인터페이스에 새로운 멤버를 추가하더라도, 해당 인터페이스를 이미 구현하고 있는 클래스들이 새로운 멤버를 즉시 구현하지 않아도 컴파일 에러가 발생하지 않도록 할 수 있습니다.

    interface ILogger
    {
        void WriteLog(string message);
        void WriteError(string error) // 새로운 메서드 추가
        {
            WriteLog($"Error: {error}"); // 기본 구현 제공
        }
    }

    이 경우, ILogger를 구현하는 클래스는 WriteLog만 구현해도 되며, WriteError는 인터페이스의 기본 구현을 사용할 수 있습니다.

추상 클래스 (Abstract Class)

추상 클래스abstract 키워드를 사용하여 선언하는 클래스입니다. 추상 클래스는 그 자체로는 객체를 생성할 수 없으며, 다른 클래스들이 상속받아 사용하기 위한 목적으로 만들어집니다.

  • 추상 클래스의 특징
    추상 클래스는 일반 클래스와 마찬가지로 필드, 속성, 일반 메서드(구현부가 있는 메서드)를 가질 수 있습니다. 또한, abstract 키워드를 사용하여 추상 메서드를 가질 수 있습니다. 추상 메서드는 선언만 있고 구현부는 없습니다.

    abstract class AbstractBase
    {
        public abstract void SomeMethod(); // 추상 메서드 (구현부 없음)
        // 일반 메서드나 필드 등 다른 멤버를 가질 수 있음
    }
  • 추상 클래스 상속
    추상 클래스를 상속받는 일반(구체) 클래스는 부모 추상 클래스에 선언된 모든 추상 메서드를 반드시 override 키워드를 사용하여 구현해야 합니다.

    class Derived : AbstractBase
    {
        public override void SomeMethod() // 추상 메서드 구현
        {
            // 메서드 구현 내용
        }
    }

    추상 클래스도 다른 추상 클래스를 상속받을 수 있습니다. 이 경우, 자식 추상 클래스는 부모 추상 클래스의 추상 메서드를 구현할 필요가 없지만, 해당 자식 추상 클래스를 상속받는 구체 클래스는 부모와 자식 추상 클래스의 모든 추상 메서드를 구현해야 합니다.

인터페이스와 추상 클래스의 차이점

인터페이스와 추상 클래스는 모두 직접 인스턴스를 생성할 수 없으며, 다른 클래스가 이를 구현 또는 상속받아 사용한다는 공통점이 있습니다. 하지만 둘 사이에는 중요한 차이점이 있습니다.

구분인터페이스 (Interface)추상 클래스 (Abstract Class)
멤버 구성메서드, 속성, 이벤트, 인덱서의 선언만 가능 (기본 구현 메서드 제외)필드, 속성, 일반 메서드, 추상 메서드 등 모든 멤버 구성 가능
구현/상속클래스는 여러 인터페이스를 구현(implement) 할 수 있다.클래스는 단 하나의 추상 클래스(또는 일반 클래스)를 상속(inherit) 할 수 있다.
목적클래스가 가져야 할 기능에 대한 계약(Contract) 정의관련 클래스들 간의 공통적인 속성과 행동 정의 및 기본 구현 제공
인스턴스화직접 인스턴스 생성 불가직접 인스턴스 생성 불가

요약하자면, 인터페이스는 '무엇을 할 수 있다'는 기능을 정의하는 데 중점을 두어 다중 구현을 통해 객체의 다양한 능력을 표현할 때 유용하며, 추상 클래스는 '무엇이다'라는 공통적인 특징을 정의하고 부분적인 구현을 제공하여 관련 클래스들의 기본 틀을 제공할 때 주로 사용됩니다.

인터페이스와 추상 클래스를 잘 이해하고 활용하면 더욱 유연하고 확장 가능한 객체 지향적인 코드를 작성할 수 있습니다.

profile
C#, Unity

0개의 댓글