<C#에서 다중 상속을 사용하지 않는 이유>

  • 다이아몬드 문제

다중 상속을 사용하면 한 개의 클래스가 두 개 이상의 부모 클래스로부터 동일한 맴버를 상속받는다.

A라는 클래스를 B와 C가 상속받는다고 해보자.

D라는 클래스가 B와 C를 상속받게 된다면 결국엔 A를 상속받은 것과 같게 된다. 이것을 다이아몬드 모양으로 상속받는다고 한다. 다이아몬드로 B가 상속받은 A 클래스와 C가 상속받은 A가 동일함으로써 어떤 부모 클래스의 맴버를 사용해야할지 모호해지는 문제가 생겨난다.

  • 설계의 복잡성 증가

다중 상속을 하게 되면 어떤 클래스로부터 어떤 맴버를 상속을 받아야할지 상속 관계를 파악하기 어려워지며, 클래스 간의 관계가 복잡해진다.

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

마찬가지로 같은 변수명이 있을 수 있고 그로 인해 중첩이 되어 사용할 수 없는 경우가 나타날 수 있다.

  • 일관성과 단순성 유지

그로 인해 C#은 일관성과 단순성을 유지하고 있다.

 

<인터페이스를 사용하는 이유>

  • 코드의 재사용성

우리는 변수를 쓰다보니 조금 더 함축해서 다양하게 쓰고 싶어 배열을 사용하였고, 코드들에 대한 일련 묶음들을 재사용 하고 싶기 때문에 메서드를 만들었고, 메서드나 필드를 한 곳에 뭉쳐 사용하고 싶기 때문에 Struct나 Class를 만들었다. 이처럼 동일한 코드들을 계속 재구현하지 않고 재사용하기 위해 인터페이스를 사용한다.

  • 다중 상속 제공
  • 유연한 설계

인터페이스는 구현을 제시할 뿐 실제 구현은 클래스가 하기 때문에 구현부와 제시부가 연관되지 않아도 된다.

 

 

인터페이스(Interface)

클래스가 구현해야하는 맴버들을 정의하는 것. 클래스에 대한 제약 조건을 건다.

클래스가 인터페이스를 구현할 경우, 모든 인터페이스 맴버들을 구현해야하며, 다중 상속을 지원한다.

 

인터페이스 구현

인터페이스를 구현할 때는 interface라는 키보드를 사용한다. 대표적인 규칙으로 이름이 I(대문자i)로 시작한다.

// 아이템을 사용할 수 있는 인터페이스 정의
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);
}

 

<인터페이스와 추상클래스>

인터페이스

- 추상적인 동작만 정의하고 구현을 아예 갖지 않는다.

- 클래스가 아니며, 다중 상속이 가능하다.

- 클래스 간의 결합도를 낮추고, 유연한 상호작용이 가능하다.

- 코드의 재사용성과 확장성을 향상시킨다.

- 인터페이스를 구현하는 클래스가 모든 동작을 구현해야하기 때문에 작업량이 많다.

 

 

추상클래스

- 일부 동작의 구현을 가지고 구현을 할 수 있다.

- 단일상속만 가능하다.

- 공통된 동작을 추상화하여 코드의 중복을 방지하고 확장성을 제공한다.

- 구현된 동작을 가지고 있어 하위 클래스에서 재정의하지 않아도 될 때 유용하다.

- 다중 상속이 불가능하고, 상속으로 밀접하게 결합된 클래스로 유연성이 제한된다.

 

 

열거형 (Enums)

서로 연관된 상수들의 집합. 열거형의 상수 값 은 정수 값이다.

- 가독성
- 자기 문서화
- switch문과 호완성

 

열거형 구현

// 열거형 정의
public enum Month
{
    January = 1,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December
}

internal class Program
{
    static void Main(string[] args)
    {
        // 처리하는 함수
        static void ProcessMonth(int month)
        {
            if (month >= (int)Month.January && month <= (int)Month.December)
            {
                Month selectedMonth = (Month)month;
                Console.WriteLine("선택한 월은 {0}입니다.", selectedMonth);
                // 월에 따른 처리 로직 추가
            }
            else
            {
                Console.WriteLine("올바른 월을 입력해주세요.");
            }
        }

        // 실행
        int userInput = 7; // 사용자 입력 예시
        ProcessMonth(userInput);
    }
}

 

 

+ Recent posts