인터페이스 (Interface)

이승한·2023년 7월 8일
0

CSharp

목록 보기
9/25

이번에는
추상 클래스와 인터페이스에 대해 알아보자.

추상클래스

행위에 강요를 주는 문법이라 생각하면 된다.

class Program
{
	class Monster
    {
    	public virtual void Shout() {}
    }
    class Orc : Monster
    {
    	public override void Shout()
    	{
        	Console.WriteLine("록타르 오가르!);
    	}
    }
    class Skeleton : Monster
    {
    	public override void Shout()
        {
        	Console.WriteLine("끼에엑!!");
        }
    }
}

몬스터라면 꼭 Shout을 정의해야한다고 가정을 해보면
이걸 강제 할수있는 방법이 바로 추상 클래스를 사용하는 것이다.

제약 : Monster라면 반드시 Shout 함수를 오버라이딩 해야한다.

class Program
{
	abstract class Monster //추상클래스
    {
    	public abstract void Shout(); //추상클래스니까 정의를 해주면 안된다.
    }
    
    class Orc : Monster
    {
    	public override void Shout()
    	{
        	Console.WriteLine("록타르 오가르!);
    	}
    }
    class Skeleton : Monster
    {
    	public override void Shout()
        {
        	Console.WriteLine("끼에엑!!");
        }
    }

	static void Main(string[] args)
	{
		//Monster mon = new Monster(); //추상클래스는 더이상 인스턴스를 만들수 없다.
	}
}

이러한 강제를 여러개 할수있는데 Flyable 이라는 추상클래스를 만들고
FlyableOrc를 만든다는 상황이라면

abstract class Monster //추상클래스
{
    public abstract void Shout();
}
abstract class Flyable
{
	public abstract void Fly();	
}

class FlyableOrc : Orc,Flyable
{
	//오류가 난다. C++에서는 다중 상속이 가능하지만 C#에서는 안된다.
}

다중상속을 추천하지않는데
FlyableOrc 처럼 Orc,Skeleton의 혼종인 SkeletonOrc가 있다고 하면
Shout를 실행하면 과연 Orc의 Shout를 콜해야하는지 Skeleton의 Shout를 콜해야하는지 꼬여버리는 문제가 발생한다. 이러한 문제처럼 C#에서는 문법적으로 다중 상속을 막아두었다.

그럼 무엇이 문제인지 보자면,
같은 시그니처의 인터페이스인 같은 이름의 함수가 각기 다르게 구현되어 있는것이 충돌해서 문제

그래서 인터페이스는 물려주되 구현부는 직접하는 문법이 있다.

C#에서 interface 라는 문법인데

class Program
{
	abstract class Monster
    {
    	public abstract void Shout();
    }
    
    interface IFlyable //인터페이스로 구현하면 I를 붙여주는게 전통 (안붙여도됌)
    {
    	void Fly();  //public이던 private 이던 상관없이 형태만 써주면 됌
        //
    }
    
    class Orc : Monster
    {
    	public override void Shout()
    	{
        	Console.WriteLine("록타르 오가르!);
    	}
    }
    
    
    class FlyableOrc : Orc,IFlyable
    {
    	public void Fly()
        {
        	//인터페이스 함수 구현
        }
    }
    
    static void DoFly(IFlyable flyable)
    {
    	//IFlyable 인터페이스를 가진 인자를 받아야 함
    	flyable.Fly(); // 당연히 flyable 함수 사용가능
    }
    
    static void Main(string[] args)
    {
    //또한 인터페이스로 선언된 변수는 인터페이스를 가지고있는 클래스를 저장할수있다
    
    IFlyable orc = new FlyableOrc();
    DoFly(orc); 메인함수에서 IFlyable을 내포하고있는 변수만이 DoFly를 호출할 수있다.
    }
}

정리해보자면,

추상클래스와 인터페이스를 사용하는 이유는 특정 클래스가 특정 시그니처의 기능을 제공하기를 원해서 사용하는 방법이 추상화 였고 추상화로 만들었을 때 단점으로 여러개의 부모를 가질 수 없으니 사용할 수 있는 범위가 한정적이라는게 문제이고 추상화보다 인터페이스를 사용하는게 유연성 있게 사용할 수 있다.
인터페이스를 사용할 때는 구현하지않고 어떤 모양으로 되어있는 함수인지만 나타내주고
인터페이스를 가지고있으면 해당 함수를 반드시 구현해야하고 또한 인터페이스는 여러개를 가질 수 있다.

0개의 댓글