C# 문법 4주차 - 인터페이스

Amberjack·2024년 1월 2일
0

C# 문법

목록 보기
23/44

⚠️ 다중 상속을 사용하지 않는 이유?

다중 상속의 문제!!!

💠 다이아몬드 문제(Diamond Problem)

다중 상속을 허용하면 한 클래스가 두 개 이상의 부모 클래스로부터 동일한 멤버를 상속받을 수 있다. 이 경우, 같은 이름의 멤버를 가지고 있을 때 어떤 부모 클래스의 멤버를 사용해야 할 지 모호해진다.

예를 들어, 아래와 같이 B, C 클래스가 A 클래스를 상속 받고, D 클래스가 B, C 클래스를 상속 받는 경우를 가정해보자.

B, C 클래스가 A를 상속하는 것을 아래와 같이 바꿔 표시할 수 있다.

이 경우, B와 C가 A에서 물려받은 멤버 a가 있다고 가정해보자.
이 a를 D가 사용하려 할 때, B와 C 중 어떤 부모 클래스의 멤버 a를 사용해야 할 지 모호해지게 된다.

😥 설계의 복잡성 증가

다중 상속을 허용하면 클래스 간의 관계가 복잡해진다. 당장 위의 다이아몬드 문제의 경우에서처럼 어떤 클래스로부터 어떤 멤버를 상속받을지 결정하기 위해 코드가 복잡해질 수 있다. 이로 인해 클래스 간의 상속 관계 파악이 어려워지고 코드의 유지 보수성이 저하되게 된다.

😣 이름 충돌과 충돌 해결의 어려움

다중 상속을 허용하면 여러 부모 클래스로부터 상속받은 멤버들의 이름이 충돌할 수 있다. 위의 다이아몬드 문제의 경우, B와 C 클래스 모두 a라는 멤버를 상속 받았기 때문에, D에서 a를 사용하기 위해서는 멤버를 재정의하거나 명시적으로 부모 클래스를 지정해야 할 수 있다. 이는 코드의 복잡성을 증가시키고 오류 발생 가능성을 높이게 된다.

😊 설계의 일관성과 단순성 유지

C#은 단일 상속을 통해 설계의 일관성과 단순성을 유지하고자 한다. 단일 상속을 통해 클래스 간의 관계를 명확하게 만들고 가독성과 이해도를 높일 수 있다. 또한 인터페이스를 사용하여 다중 상속이 필요한 경우에 유사한 기능을 구현할 수 있다.

🖥️ 인터페이스(Interface)

👉 인터페이스를 사용하는 이유

  • 코드의 재사용성

    인터페이스를 사용하면 다른 클래스에서 해당 인터페이스를 구현하여 동일한 기능을 공유할 수 있다. 인터페이스를 통해 다양한 클래스가 동일한 동작을 수행할 수 있으므로 코드의 재사용성이 향상된다.
  • 다중 상속 제공

    C#은 인터페이스의 다중 상속을 지원한다. 클래스가 여러 인터페이스를 구현함으로써 여러 개의 기능을 조합할 수 있다.
  • 유연한 설계

    인터페이스를 사용하면 클래스와 인터페이스 간에 느슨한 결합을 형성할 수 있다. 클래스의 내부 구현에 대한 변경 없이 인터페이스의 동작을 변경하거나 새로운 인터페이스를 추가할 수 있기에 유연하고 확장 가능한 소프트웨어 설계를 가능케 한다.

📌 인터페이스의 특징

  • 인터페이스란 클래스가 구현해야 하는 멤버들을 정의하는 것!
  • 인터페이스는 클래스의 일종이 아니며, 클래스에 대한 제약 조건을 명시하는 것!
  • 클래스가 인터페이스를 구현할 경우, 모든 인터페이스 멤버를 구현해야 한다.
  • 다중 상속을 지원한다.

⌨️ 인터페이스 구현

  • 인터페이스 및 멤버 정의하기(인터페이스의 이름은 보통 I로 시작한다)
interface IMyInterface
{
    void Method1();
    int Method2(string str);
}
  • 인터페이스 구현하기
class MyClass : IMyInterface
{
    public void Method1()
    {
        // 구현
    }

    public int Method2(string str)
    {
        // 구현
        return 0;
    }
}

▪️ 사용 예제) 캐릭터의 움직임을 구현해보자!

  1. 인터페이스 정의하기
public interface IMovable
{
    void Move(int x, int y); // 이동 메서드 선언
}
  1. 인터페이스를 구현하는 클래스 생성하기
public class Player : IMovable
{
    public void Move(int x, int y)
    {
        // 플레이어의 이동 구현
    }
}

public class Enemy : IMovable
{
    public void Move(int x, int y)
    {
        // 적의 이동 구현
    }
}
  1. 인터페이스를 사용하여 객체 이동하기
IMovable movableObject1 = new Player();
IMovable movableObject2 = new Enemy();

movableObject1.Move(5, 0); // 플레이어 이동
movableObject2.Move(1, 9); // 적 이동

▪️ 사용 예제) 아이템 사용 구현 예제

// 아이템을 사용할 수 있는 인터페이스
public interface IUsable
{
    void Use();
}

// 아이템 클래스
public class Item : IUsable
{
    public string Name { get; set; }

    public void Use()
    {
        Console.WriteLine("아이템 {0}을 사용했습니다.", Name);
    }
}

// 플레이어 클래스
public class Player
{
    public void UseItem(IUsable item)
    {
        item.Use();
    }
}

// 게임 실행
static void Main()
{
    Player player = new Player();
    Item item = new Item { Name = "Health Potion" };
    player.UseItem(item);
}

▪️ 다중 상속 구현 예제) 아이템 줍고 버리기

// 인터페이스 1
public interface IItemPickable
{
    void PickUp();
}

// 인터페이스 2
public interface IDroppable
{
    void Drop();
}

// 아이템 클래스
public class Item : IItemPickable, IDroppable
{
    public string Name { get; set; }

    public void PickUp()
    {
        Console.WriteLine("아이템 {0}을 주웠습니다.", Name);
    }

    public void Drop()
    {
        Console.WriteLine("아이템 {0}을 버렸습니다.", Name);
    }
}

// 플레이어 클래스
public class Player
{
    public void InteractWithItem(IItemPickable item)
    {
        item.PickUp();
    }

    public void DropItem(IDroppable item)
    {
        item.Drop();
    }
}

// 게임 실행
static void Main()
{
    Player player = new Player();
    Item item = new Item { Name = "Sword" };

    // 아이템 주울 수 있음
    player.InteractWithItem(item);

    // 아이템 버릴 수 있음
    player.DropItem(item);
}

🥊 인터페이스 VS 추상클래스

▪️ 인터페이스의 특징과 장단점

  • 인터페이스는 추상적인 동작만 정의하고, 구현을 갖지 않는다!
  • 다중 상속이 가능! 여러 클래스가 동일한 인터페이스를 구현할 수 있다.
  • 클래스들 간의 결합도를 낮추고, 유연한 상호작용을 가능하게 한다.
  • 코드의 재사용성과 확장성 향상
  • 단점으로 인터페이스를 구현하는 클래스가 모든 동작을 구현해야 하기 때문에 작업량이 증가할 수 있다.

▪️ 추상클래스의 특징과 장단점

  • 추상 클래스는 일부 동작의 구현을 가지며, 추상 메서드를 포함할 수 있다.
  • 단일 상속만 가능! 다른 클래스와 함께 상속 계층 구조를 형성할 수 있다.
  • 공통된 동작을 추상화하여 코드의 중복을 방지하고, 확장성을 제공한다.
  • 구현된 동작을 가지고 있기 때문에, 하위 클래스에서 재정의하지 않아도 될 경우 유용하다.
  • 단점으로 다중 상속이 불가능하고, 상속을 통해 밀접하게 결합된 클래스들을 형성하므로 유연성이 제한될 수 있다.

0개의 댓글