[C#] 인터페이스(interface)란?

Arthur·2024년 1월 8일
0
post-thumbnail

이 글의 주요 키워드 및 내용 요약


이 글의 내용을 핵심 키워드와 내용으로 요약한 것입니다.
시각적으로 한 눈에 보이는 것이 더욱 기억에 잘 남기 때문에 이렇게 마인드맵으로 그려봤습니다.


ChatGPT 요약

인터페이스는 서로 다른 시스템 간 정보 교환의 경계면을 나타내며, 프로그래밍에서는 메서드 집합으로 사용자 기기를 동작시키는 시스템을 추상화한다. C#에서의 인터페이스는 클래스가 특정 메서드를 제공해야 하는 규약으로, 다형성과 코드 일관성을 제공한다. IList와 IList<T>의 차이는 제네릭 여부와 타입 안정성에 있다. 인터페이스를 사용하면 코드의 유연성과 표준화가 높아지며, ArrayList와 List<T>는 이를 구현한 예시이다.



인터페이스(interface)란?


서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면이다.
즉, 사용자 기기를 쉽게 동작시키는데 도움을 주는 시스템을 의미한다.
<위키피디아 - 인터페이스(컴퓨팅)>

인터페이스는 상담히 범용적인 부분에서 사용되는 용어입니다.
프로그래밍 언어에서만 주로 사용되는 단어가 아닙니다.

인터페이스는 사용자가 기기를 쉽게 동작할 수 있도록 복잡한 내부적인 시스템을 추상화해서 제공합니다.

(네이버 메인 페이지)

웹에서는 유저가 편리하게 사용을 할 수 있도록 검색 시스템 부터 다양한 인터페이스를 제공합니다.


(게임 리그 오브 레전드)

게임에서는 좀 더 게임의 개성에 맞게 인터페이스가 구축되어 있습니다.
유저는 이런 인터페이스들이 내부적으로 어떻게 작동하는지 몰라도 편하게 사용할 수 있습니다.



C#에서의 인터페이스


인터페이스는 메서드 집합을 의미합니다.
이 인터페이스를 구현하는 클래스는 이러한 메서드를 제공해야 합니다.

여기서 메서드를 제공해야 한다는 것은 인터페이스에 정의된 메서드를 구현(implementation) 해야 한다는 것을 의미합니다. 구현을 하지 않으면 컴파일 에러가 발생합니다.


인터페이스의 특징

  • 한 클래스는 여러개의 인터페이스를 구현할 수 있습니다.
  • 인터페이스 정의 시 메서드, 속성에 public과 같은 접근 제한자를 사용하지 않습니다.
    • 인터페이스의 메서드, 속성은 자동적으로 'public'으로 간주됩니다.
      따라서 개발자가 명시적으로 'public' 키워드를 적으면 컴파일 에러가 발생합니다.
  • C#에서는 인터페이스로부터 직접 new를 사용하여 객체를 생성할 수 없습니다.
    • 인터페이스는 참조 형식이지만 인스턴스를 만들 수 없습니다.
      New 는 클래스 또는 구조체의 인스턴스를 만드는 데만 사용할 수 있습니다.
    • 인터페이스는 추상적인 개념이므로, 직접적으로 인스턴스화 할 수 없습니다.
    • 클래스를 통해 구체적인 구현을 제공한 후, 해당 클래스의 인스턴스를 생성하여 사용해야 합니다.

C#에서 제공되는 인터페이스 중에 IList의 코드를 일부분 가져와 봤습니다.

using System.Runtime.InteropServices;

namespace System.Collections
{
    public interface IList : ICollection, IEnumerable
    {
        int Add(object value);
        
        bool Contains(object value);
        
        void Clear();
        
        int IndexOf(object value);

        void Insert(int index, object value);

        void Remove(object value);

        void RemoveAt(int index);
    }
}

IList를 구현하는 클래스는 위 7개의 메서드를 필수적으로 구현해야 합니다.

ArrayList는 IList를 구현하는 클래스 중에 하나입니다.

namespace System.Collections
{
    public class ArrayList : IList, ICollection, IEnumerable, ICloneable
    {
        public virtual int Add(object value)
        {
        	// ...
        }
        
        public virtual bool Contains(object item)
        {
        	// ...
        }
       
        public virtual void Clear()
        {
        	// ...
        }
        
       public virtual void Insert(int index, object value)
        {
        	// ...
        }
        
        public virtual void Remove(object obj)
        {
        	// ...
        }
        
        public virtual void RemoveAt(int index)
        {
        	// ...
        }
    }
}

ArrayList의 코드를 보면 IList의 메서드를 구현해 놓았습니다.

ArrayList(인터페이스 구현 클래스)와 IList(인터페이스)를 통해 어떻게 사용하는지 알게 되었습니다.

그런데 여기서 Add(), Remove()와 같은 메서드를 그냥 클래스에서 직접 구현할 수도 있는데,
굳이 IList를 인터페이스로 정의해서 사용하는지 찾아보게 되었습니다.



IList를 interface로 정의한 이유는?


IList를 인터페이스로 정의하는 이유는 다형성(Polymorphism)을 지원하고,
다양한 컬렉션 타입을 일관된 방식으로 다룰 수 있도록 하는 데 있습니다.

  • 다형성 및 추상화
    • 다양한 컬렉션 타입을 하나의 일반적인 형식으로 다룰 수 있습니다.
    • 코드의 유연성을 높이고, 컬렉션을 다룰 때 일관된 방식으로 작업할 수 있도록 합니다.
  • 인터페이스 구현을 통한 표준화
    • 인터페이스에 설계 되어 있는 메서드와 속성을 통해 표준화된 작업이 가능해집니다.
    • 해당 인터페이스를 통해 일관된 API에 접근할 수 있습니다.
  • 클래스 간 결합도 감소
    • 코드가 특정 클래스에 의존하는 대신 인터페이스에 의존함으로써 코드의 유연성과 유지보수성이 향상됩니다.

C#을 만들고 유지보수한 개발자들의 의도를 정확하게 알 수는 없지만,
위와 같은 인터페이스의 장점을 통해 추론해 볼 수 있습니다.

그리고 만약에 나만의 List를 만든다면, IList 인터페이스를 구현하면 일관성을 유지할 수 있습니다.



IList와 IList<T>의 차이점은 무엇일까?


IList는 제네릭이 아닌 인터페이스로, 어떤 타입의 요소라도 다룰 수 있지만, 컴파일 시에 타입 안정성이 보장되지 않습니다.
IList<T>는 제네릭 인터페이스로, 특정한 타입의 요소를 다루며, 컴파일 시에 타입 안정성이 보장되어 잘못된 타입의 요소가 추가되는 것을 방지합니다.


제네릭이란?
데이터의 타입(data type)을 일반화한다(generalize)는 것을 의미합니다.
제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법입니다.
이렇게 컴파일 시에 미리 타입 검사(type check)를 수행하면 다음과 같은 장점을 가집니다.


인터페이스에 관한 글인데 갑자기 제네릭에 대한 얘기가 나와서 당황하실 수 있습니다.

하지만 이 두 개의 인터페이스를 통해 인터페이스의 장점을 알아 볼 수 있습니다.
그 장점은 특정 클래스를 상속 받지 않고 인터페이스를 구현하면서 오는 코드의 유연성, 코드의 일관성과 표준화입니다.


인터페이스의 장점을 살려서 사용하고 있는 대표적인 클래스에는 ArrayList와 List<T>가 있습니다.

ArrayList


public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
	// ...
}

List<T>

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
{
    // ...
}

IList<T>는 제네릭 IList를 구현하면서 제네릭에 필요한 인터페이스를 제공하고 있습니다.
반대로 ArrayList는 제네릭 컬렉션이 아니기 때문에 제네릭 IList를 구현하지 않았습니다.

만약에 나만의 List를 제네릭으로 만든다면 IList<T>와 IList를 구현하고,
제네릭 List가 아니라면 IList 인터페이스만 구현해주면 됩니다.

제네릭 컬렉션에 필요한 인터페이스를 제공해주기 때문에 코드의 유연성과 유지보수성이 올라가게 됩니다.



참고 자료


  • csharpstudy - C# 인터페이스 => 링크
  • MS Docs - interface(C# 참조) => 링크
  • TCP School - 제네릭의 개념 => 링크
  • ChatGPT
profile
기술에 대한 고민과 배운 것을 회고하는 게임 서버 개발자의 블로그입니다.

0개의 댓글