IT/학습

인터페이스(interface) 와 형변환

wh011202 2024. 12. 13. 14:44

일종의 약속,강제로 제약을 만들어냄.
인터페이스에서 만든 함수는 적용받은 곳에선 무조건 만들어야함.
그걸 강제로 제약건다함.
이 인터페이스는 한 클래스에서도 여러개 적용가능.
공통된 기능을 추려내서 인터페이스로 만들면 편함.
다형성을 활용하여 필요시 인터페이스 형을 바꿀수도 있음.

interface Interctable
{
    void 반드시구현해야할함수();
}


인터페이스는 기능들만의 집합체이다.

 

인터페이스는 여러개 중복해서 룰을 적용 하는것이 가능하다
예시로 들어서 이런게 가능하다 .

class Plane : IDrivable,IAppDomainSetup,ICloneable

 

아래는 실 사용시 예시다

    //룰들의 집합체
    interface IDrivable //여러개를 한 클래스에 적용시킬수있다.
    {
        //int a;
        //필드를 가질수가없다.

        //인터페이스는 메서드 명만 정의 가능.
        //기능내부 구현이 불가능하다.
        //무조건 적용 받은 클래스 내부에서만 정의 가능.
        void Drive();
    }
class Plane : IDrivable
{
    float _x;
    float _y;

    public void Drive()
    {
        Console.WriteLine("활주로로 이동");
    }

    public void Fly()
    {
        Console.WriteLine("비행기 난다요");
    }


}

class Vehicle : IDrivable
{
    int x;
    int y;

    public void Drive()
    {
        Console.WriteLine("무브무브");
    }

    public void LoadPeople()
    {
        Console.WriteLine("길거리에서 승객 태우기");
    }
}

 

위에는 정의 부분이고 아래가 실 사용할 메인부분이다.

Plane plane = new Plane();
Vehicle vehicle = new Vehicle();

//10개 공간생성
//필요할 경우 적용된 인터페이스 형으로 바꿀수있음.
IDrivable[] Autobots = new IDrivable[10];

Autobots[0] = plane;
Autobots[1] = vehicle;

//인터페이스를 적용받은 애들은,
//인터페이스에 정의된 함수를 구현했을거란 보장이 있음.
foreach (var robots in Autobots)
{
    robots.Drive();
}

 

결과값은 이렇다.

 

 

이런식으로 사용하면서 인터페이스를 형변환처럼 사용을 할수가 있다.

 

 

이번엔 is 와 as를 사용한 예시를 하나 더 들어보자 

 

interface IAttackable
{
    void Attack();
}

class Sword : IAttackable
{

    public void Attack()
    {
        Console.WriteLine("칼 공격");
    }
    public void MeleeAttack()
    {
        Console.WriteLine("근접 공격을 수행합니다.");
    }
}

class Bow : IAttackable
{
    public void Snipe()
    {
        Console.WriteLine("저격을 수행합니다.");
    }
    public void Attack()
    {
        Console.WriteLine("활 공격");
    }
}

class Player
{
    IAttackable _weapon;

    public void EquipWeapon(IAttackable weapon)
    {
        _weapon = weapon;
        Console.WriteLine("무기 장착완료");
    }


    public void PerformAttack()
    {
        if (_weapon == null)
        {
            Console.WriteLine("무기가 없습니다. " +
                "기본공격을 수행함니다.");
        }
        //is as 
        //is 확인 -> 캐스팅 가능한지 확이할떄,참 거짓을 반환
        //as 만약 옆에껄 보고 캐스팅 가능하면 변환하고 아니면 null
        else if (_weapon is Bow)//웨폰이 활이라면
        {
            //웨펀을 보우형으로 바꾸고 스나이프 실행
            (_weapon as Bow).Snipe();
        }
        else if (_weapon is Sword)//웨폰이 검이라면
        {
            //웨펀을 소드형으로 바꾸고 밀리어택 실행
            (_weapon as Sword).MeleeAttack();

        }
        else
        {
            _weapon.Attack();
        }

    }
}

이런식으로 위험한 코드도 걸러서 사용할수있어서 매우좋다. 아래는 메인이다.

 

 

            Player player = new Player();

            //player.EquipWeapon(new Bow());
            //player.EquipWeapon(new Sword());
            //위에걸 아래처럼 가능
            Bow bow = new Bow();
            player.EquipWeapon(bow);

            player.PerformAttack();

이렇게 넣어주면? 아래처럼 나온다.

분명 넣어준건 Bow 클래스인데 

들어가는 인자는

public void EquipWeapon(IAttackable weapon)

 

이걸 보면 인터페이스이다. 

 

이런식으로 형변환? 식으로 들어가서 정상작동하게 해주는게 인터페이스 적용이다.

 

위 코드의 결과값이다.

 

 

그리고 제네릭이랑도 같이 쓸수가 있는데

 

 //인터페이스와 제네릭

 interface IAndroid
 {
     //안드로이드폰은 무조건 구글 아이디가 있어야한다.
     string GoogleID { get; }//프로퍼티를 무조건 강제할수있음.
 }

 class Phone { }

 class Galaxy : Phone, IAndroid
 {
     string _googleId;
     public string GoogleID
     {
         get { return _googleId; }
     }
 }
 class Xperia : Phone, IAndroid
 {
     string _googleId;
     public string GoogleID
     {
         get { return _googleId; }
     }
 }
 class Pixel : Phone, IAndroid
 {
     string _googleId;
     public string GoogleID
     {
         get { return _googleId; }
     }
 }
 class IPhone : Phone { }

 class GooglePlay<T> where T : IAndroid
 {
     T phone;
 }

 

//where 조건에 아이폰이 정의받지 않는게 포함되있어서 안됨.
//GooglePlay<IPhone> myAsset = new GooglePlay<IPhone>();
GooglePlay<Galaxy> myAsset = new GooglePlay<Galaxy>();

이런식으로 제한을 걸면 안드로이드폰만 생성이 가능해지는 제한도 걸수가 있다.

 

 

구글플레이 부분 적용을 이렇게 바꾸면

            GooglePlay<IPhone> myAsset = new GooglePlay<IPhone>();

메인에서 이코드도 사용이 가능해진다.

 

이런식으로 제약을 잘걸면 넣으면 안될걸 거르는것도 되고, 겸사겸사 공용메서드도 사용할수있고 심지어 하나의 배열에 넣어서 한번에 같은메서드 실행같은 경우도 가능하다.

 

묶는데 머리아프겠지만 잘 사용하면 할수록 코드가 짧아지고 편해질거같다.