2022. 2. 28. 00:00ㆍCSharp/Design Pattern
Adapter
호환되지 않는 인터페이스를 가진 개체가 서로 협업할 수 있도록 하는 구조적 디자인 패턴
** 구조적 패턴 **
: 구조를 유연하고 효율적으로 유지하면서 개체와 클래스를 더 큰 구조로 조립하는 방법을 설명
간단히 UML 로 표현하자면 아래와 같다.
Client : adapter 를 사용 하여 adaptee 쪽 동작을 하려는 사용자
Adaptee : client 에 노출된 interface 만으로 접근할 수 없거나 사용할 수 없는 객체 또는 library
Target Interface : client 가 접근할 수 있으며 adapter 가 구현하는 interface. 이 interface 를 통해 client 가 adaptee 를 호출할 수 있다.
Adapter : client 와 adaptee 중간에서 둘을 연결 시켜주는 역할. target interface 를 구현하며 client 가 target interface 를 통해 adapter 에 요청을 보내면 adapter 는 adaptee 가 이해할 수 있는 방법으로 호출하고 adaptee 는 요청을 처리한다.
다음과 같은 상황을 가정해 보자
게임에서 검을 주 무기로 다루는 특정 케릭터가 있다.
이검은 근접 무기이다.
해당 무기는 attack 시 damage 만 parameter 로 전달 받고 해당 하는 damage 를 적에게 입힌다.
그런데 이 특정 케릭터는 보조 무기로 총을 사용 할 수 있다.
하지만 총은 distance 와 damage 를 parameter 로 받고 적과의 distance 에 따라 damage 가 변화한다.
검을 주무기로 다루는 케릭터는 먼거리에서 총을 맞출 수 없고 검을 사용하다가 그 거리에서 총을 사용하므로
특정 distance 까지 이동한 후 damage 를 준다.
이럴 경우 하나의 attack 이라는 interface 를 가지고 어떻게 검과 총의 attack 과 fire 를 호출 할 수 있을까?
아래 코드를 보자.
Target Interface
public interface IMeleeAttack
{
void Attack(int damage);
}
Sword class (IMeleeAttack 을 구현한 주무기)
public class Sword: IMeleeAttack
{
public void Attack(int damage) => Console.WriteLine($"검으로 {damage} damage 를 주었다.");
}
Gun class (IRangedAttack 울 구현한 보조무기) 우리는 이 interface 를 IAttack 을 통해 호출해야 한다.
public interface IRangedAttack
{
void Fire(int distance, int damage);
}
public abstract class NormalRangedWeapon:IRangedAttack
{
public abstract void Fire(int distance, int damage);
protected virtual double GetReduceDamage(int distance) => distance switch
{
> 10 => 0.1,
>= 5 => 0.5,
> 0 => 1,
_ => 0
};
}
public class Gun: NormalRangedWeapon
{
public override void Fire(int distance, int damage)=>Console.WriteLine($"총으로 {damage * GetReduceDamage(distance)} damage 를 주었다.");
}
Adaptor
public class MeleeAttackAdapter : IMeleeAttack
{
private readonly Gun _adaptee;
public MeleeAttackAdapter(Gun gun) => _adaptee = gun;
public void Attack(int damage)
{
// gun 관련 기본 거리를 지정한다.
_adaptee.Fire(5, damage);
}
}
사용법
int attackDamage = 10;
IMeleeAttack sword = new Sword();
sword.Attack(attackDamage);
IMeleeAttack adapter = new MeleeAttackAdapter(new Gun());
adapter.Attack(attackDamage);
// output
검으로 10 damage 를 주었다.
총으로 5 damage 를 주었다.
관련영상