이번에는
추상 클래스와 인터페이스에 대해 알아보자.
행위에 강요를 주는 문법이라 생각하면 된다.
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를 호출할 수있다.
}
}
정리해보자면,
추상클래스와 인터페이스를 사용하는 이유는 특정 클래스가 특정 시그니처의 기능을 제공하기를 원해서 사용하는 방법이 추상화 였고 추상화로 만들었을 때 단점으로 여러개의 부모를 가질 수 없으니 사용할 수 있는 범위가 한정적이라는게 문제이고 추상화보다 인터페이스를 사용하는게 유연성 있게 사용할 수 있다.
인터페이스를 사용할 때는 구현하지않고 어떤 모양으로 되어있는 함수인지만 나타내주고
인터페이스를 가지고있으면 해당 함수를 반드시 구현해야하고 또한 인터페이스는 여러개를 가질 수 있다.