인터페이스(interface) 와 형변환
일종의 약속,강제로 제약을 만들어냄.
인터페이스에서 만든 함수는 적용받은 곳에선 무조건 만들어야함.
그걸 강제로 제약건다함.
이 인터페이스는 한 클래스에서도 여러개 적용가능.
공통된 기능을 추려내서 인터페이스로 만들면 편함.
다형성을 활용하여 필요시 인터페이스 형을 바꿀수도 있음.
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>();
메인에서 이코드도 사용이 가능해진다.
이런식으로 제약을 잘걸면 넣으면 안될걸 거르는것도 되고, 겸사겸사 공용메서드도 사용할수있고 심지어 하나의 배열에 넣어서 한번에 같은메서드 실행같은 경우도 가능하다.
묶는데 머리아프겠지만 잘 사용하면 할수록 코드가 짧아지고 편해질거같다.