반응형
Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

개발꿈나무

[C# 교과서] 24. C# 활용(18) - 인터페이스 본문

C# 기초

[C# 교과서] 24. C# 활용(18) - 인터페이스

HYOKYE0NG 2022. 1. 21. 07:52
반응형
인터페이스

 

인터페이스는 프로그램의 표준 규약을 정하고 따를 수 있도록 강제한다.

 

인터페이스

인터페이스는 클래스 또는 구조체에 포함될 수 있는 관련 있는 메서드들을 묶어 관리하며, 인터페이스를 상속받아 그 내용을 구현하는 클래스는 인터페이스에 선언된 멤버(속성, 메서드 등)가 반드시 구현되어 있다는 보증을 한다.

 

  • 인터페이스는 interface 키워드를 사용하여 만들며 실행 가능한 코드와 데이터를 포함하지 않는다.
  • 추상 클래스처럼 다른 클래스의 멤버 이름을 미리 정의할 때 사용된다. 추상 클래스와 다른 점은 멤버 내용을 구현하지 않고 이름만 정의한다.
  • 인터페이스에는 메서드, 속성, 인덱서 및 이벤트를 정의할 수 있다.
  • 현실 세계에서 전 세계 표준과 같은 기능이다.
  • 단일 상속만 지원하는 클래스와 달리 인터페이스를 사용한 다중 상속이 가능하다.
  • 인터페이스 멤버는 액세스 한정자를 붙이지 않으며 항상 public이고, virtual 및 static을 붙일 수 없다.
  • 인터페이스 내의 모든 멤버는 기본적으로 public이다.
  • C#에서 인터페이스 이름은 대문자 I로 시작한다.
  • 인터페이스는 인스턴스화되지 않고 클래스를 사용하여 인스턴스화 된다.
  • 인터페이스는 계약(constract) 의미가 강하며 속성, 메서드, 이벤트, 인덱서 등 구조를 미리 정의한다.

 

인터페이스로 특정 멤버가 반드시 구현되어야 함을 보증하기

using System;

namespace InterfaceNote
{
    //[1] ICar 인터페이스 선언
    interface ICar
    {
        void Go(); //[A] 메서드 시그니처만 제공
    }

    //[2] ICar 인터페이스를 상속하는 Car 클래스 선언
    class Car : ICar
    {
        public void Go() => Console.WriteLine(
            "상속한 인터페이스에 정의된 모든 멤버를 반드시 구현해야한다.");
    }

    class InterfaceNote
    {
        static void Main()
        {
            var car = new Car();
            car.Go();
        }
    }
}

ICar 인터페이스를 상속받는 클래스에서 Go() 메서드를 구현하지 않는 경우 에러가 발생한다.

 

 

인터페이스 형식 개체에 인스턴스 담기

using System;

// [1] 하나의 멤버를 갖는 인터페이스 정의
public interface IRepository
{
    void Get();
}

// [2] 인터페이스를 상속하는 클래스 구현 
public class Repository : IRepository
{
    public void Get()
    {
        Console.WriteLine("Get() 메서드를 구현해야 합니다.");
    }
}

class InterfacePractice
{
    static void Main()
    {
        // [A] 인터페이스 형식 개체에 인스턴스 담기 
        IRepository repository = new Repository();
        repository.Get();
    }
}

인터페이스를 상속하는 클래스를 이용하여 인터페이스를 인스턴스화할 수 있다.

이러한 코드 모양은 리포지토리(repository) 패턴 이름으로 많이 사용된다.

 

 

생성자의 매개변수에 인터페이스 사용하기

생성자의 매개변수에 인터페이스 형식을 사용하면 해당 인터페이스를 상속하는 모든 클래스의 인스턴스를 받을 수 있다.

using System;

namespace InterfaceDemo
{
    // 배터리 표준(강제성)
    interface IBattery
    {
        string GetName(); // 메서드 시그니처만 표시
    }

    class Good : IBattery
    {
        public string GetName() => "Good";
    }

    class Bad : IBattery
    {
        public string GetName() => "Bad";
    }

    class Car
    {
        private IBattery _battery;

        //[1] 생성자의 매개 변수로 인터페이스 형식 지정
        public Car(IBattery battery)
        {
            _battery = battery; // 넘어온 개체가 _battery 필드에 저장
        }

        public void Run() => Console.WriteLine(
            "{0} 배터리를 장착한 자동차가 달립니다.", _battery.GetName());
    }

    class InterfaceDemo
    {
        static void Main(string[] args)
        {
            //[A] 넘겨주는 개체에 따라서 배터리 이름이 다르게 표시 
            var good = new Car(new Good()); good.Run();
            new Car(new Bad()).Run(); // 개체 만들기와 동시에 메서드 실행
        }
    }
}

IBattery 인터페이스를 상속하는 Good과 Bad 클래스의 인스턴스는 IBattery 인터페이스 형식을

매개변수로 받을 수 있다. 이러한 방식으로 생성자의 매개변수로 인터페이스를 사용하면, 해당 클래스의 생성자는

개체를 하나 이상 받을 수 있는 융통성이 늘어난다.

 

 

 

인터페이스를 사용한 다중 상속 구현하기

다중 상속은 클래스 하나를 콤마로 구분해서 인터페이스 하나 이상을 상속하는 것이다.

C#에서 클래스는 클래스에 대한 단일 상속만 지원하는 대신, 인터페이스는 클래스에 인터페이스를 하나 이상 상속할 수 있다.

using System;

namespace InterfaceInheritance
{
    interface IAnimal
    {
        void Eat();
    }

    interface IDog
    {
        void Yelp();
    }

    class Dog : IAnimal, IDog // 인터페이스를 사용한 다중 상속
    {
        public void Eat() => Console.WriteLine("먹다.");
        public void Yelp() => Console.WriteLine("짖다.");
    }

    class InterfaceInheritance
    {
        static void Main()
        {
            Dog dog = new Dog();
            dog.Eat();  //[A] IAnimal 인터페이스 상속
            dog.Yelp(); //[B] IDog 인터페이스 상속
        }
    }
}

Dog 클래스는 IAnimal 인터페이스와 IDog 인터페이스에서 다중 상속을 받는다.

 

 

명시적인 인터페이스 구현하기

인터페이스를 사용한 다중 상속이 이루어졌을 때 각 인터페이스에 동일한 멤버가 구현되어 있을 수 있다. 이 때는 

명시적으로 어떤 인터페이스의 멤버를 실행할 지 지정해줘야 한다.

using System;

interface IDog
{
    void Eat();
}

interface ICat
{
    void Eat();
}

class Pet : IDog, ICat
{
    void IDog.Eat() => Console.WriteLine("Dog Eat"); // [1] 명시적으로 IDog 지정

    void ICat.Eat() => Console.WriteLine("Cat Eat"); // [2] 명시적으로 ICat 지정
}

class InterfaceExplicit
{
    static void Main()
    {
        Pet pet = new Pet();
        ((IDog)pet).Eat(); // [A] pet 개체를 IDog 형식으로 형식 변환
        ((ICat)pet).Eat(); // [B] pet 개체를 ICat 형식으로 형식 변환

        IDog dog = new Pet();
        dog.Eat();
        ICat cat = new Pet();
        cat.Eat();
    }
}

IDog 인터페이스와 ICat 인터페이스를 상속받는 Pet 클래스의 인스턴스 pet에서 IDog 인터페이스의

Eat() 메서드를 실행하려면 IDog 형식으로 변환해야 한다.

 

 

인터페이스와 추상 클래스 비교하기

<추상 클래스>

  • 구현된 코드가 들어온다. 즉, 메서드 시그니처만 있는 것이 아니라 사용 가능한 실제로 구현된 메서드도 들어온다.
  • 단일상속: 기본 클래스에서 상속될 수 있다.
  • 각 멤버는 액세스 한정자를 갖는다.
  • 필드, 속성, 생성자, 소멸자, 메서드, 이벤트, 인덱서 등을 갖는다.

 

<인터페이스>

  • 인터페이스는 규약이다.
  • 구현된 코드가 없다.
  • 다중상속: 여러가지 인터페이스에서 상속 가능하다.
  • 모든 멤버는 자동으로 public이다.
  • 속성, 메서도, 이벤트와 대리자를 멤버로 갖는다.

 

 

IEnumerator 인터페이스 사용하기

using System;
using System.Collections;

class IEnumeratorDemo
{
    static void Main()
    {
        string[] names = { "닷넷코리아", "비주얼아카데미" };

        //[1] foreach 문으로 출력
        foreach (string name in names)
        {
            Console.WriteLine(name);
        }

        //[2] IEnumerator 인터페이스를 통한 데이터 출력: foreach문과 동일
        IEnumerator list = names.GetEnumerator(); // 하나씩 열거
        while (list.MoveNext()) // 값이 있는 동안 반복
        {
            Console.WriteLine(list.Current); // 현재 반복중인 데이터 출력
        }
    }
}

IEnumerator 인터페이스는 문자열 배열 등 GetEnumerator() 메서드의 결괏값을 담아

MoveNext() 메서드로 값이 있는지 확인하고, Current 속성으로 현재 반복되는 데이터를 가져다 사용할 수 있다.

 

 

IDisposable 인터페이스 사용하기

using System;

class IDisposableDemo
{
    static void Main()
    {
        Console.WriteLine("[1] 열기");
        using (var t = new Toilet())
        {
            // 특정 프로세스 종료시 자동으로 닫기 수행
            Console.WriteLine("[2] 사용");
        }
    }
}

public class Toilet : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("[3] 닫기");
    }
}

IDisposable 인터페이스를 상속하는 클래스의 Dispose() 메서드는 해당 클래스의 개체를 다 사용한 후

마지막으로 호출해서 정리하는 역할을 한다.

 

 

 

 

<Reference>

 

반응형
Comments