Adapter (Structural Pattern)

2022. 2. 28. 00:00CSharp/Design Pattern

반응형

Adapter

호환되지 않는 인터페이스를 가진 개체가 서로 협업할 수 있도록 하는 구조적 디자인 패턴

 

** 구조적 패턴 **

: 구조를 유연하고 효율적으로 유지하면서 개체와 클래스를 더 큰 구조로 조립하는 방법을 설명

 

참조 : https://dev.to/danlee0528/design-pattern-the-adapter-facade-patterns-2ipf

 

 

간단히 UML 로 표현하자면 아래와 같다. 

참조 : https://yaboong.github.io/design-pattern/2018/10/15/adapter-pattern/

 

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 는 요청을 처리한다.

 

참조 : http://www.cs.sjsu.edu/~pearce/modules/labs/ood/clinics/PatternClinic.htm

다음과 같은 상황을 가정해 보자

 

게임에서 검을 주 무기로 다루는 특정 케릭터가 있다. 

이검은 근접 무기이다. 

해당 무기는 attack 시 damage 만 parameter 로 전달 받고 해당 하는 damage 를 적에게 입힌다. 

그런데 이 특정 케릭터는 보조 무기로 총을 사용 할 수 있다.

하지만 총은 distance 와 damage 를 parameter 로 받고 적과의 distance 에 따라 damage 가 변화한다. 

검을 주무기로 다루는 케릭터는 먼거리에서 총을 맞출 수 없고 검을 사용하다가 그 거리에서 총을 사용하므로

특정 distance 까지 이동한 후 damage 를 준다. 

참조 : https://lucien0maverick.wordpress.com/tag/frostmourne/

이럴 경우 하나의 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 를 주었다.

 

 

 

관련영상

https://youtu.be/jp9guRisCvs

 

반응형

'CSharp > Design Pattern' 카테고리의 다른 글

Flyweight  (0) 2022.03.11
Facade  (0) 2022.03.10
Decorator  (0) 2022.03.09
Composite  (0) 2022.03.08
Bridge  (0) 2022.03.07