Java 디자인 패턴-10.Adapter

(Java 디자인 패턴 스터디 모집 중 : https://github.com/bluedskim/javaDesignPatterns)

Adapter(적응) 패턴

숲속의 곰이 북극에 적응하기

(출처:https://educationinaction.org/water-rocks-vocabulary/adaptation)

해결하려는 문제

  1. 인터페이스의 불일치 해결.

용도/목적

  1. 구조적Structural 패턴
  2. 어떤 인터페이스를 다른 목적의 인터페이스로 만드는 패턴.
  3. 클라이언트 소스 수정이 불가능한 경우 유용하다.

구성요소

  1. adapter(wrapper) : adaptee의 interface를 클라이언트가 원하는 target의 인터페이스로 변경하는 객체
  2. adaptee : 변경대상이 되는 객체
  3. target : 클라이언트가 원하는 인터페이스를 가지고 있는 객체
  4. 클라이언트 : target으로 변경된 adaptee를 사용하는 객체

고려사항

다른 유사한 패턴과 비교해보자 https://en.wikipedia.org/wiki/Adapter_pattern#Usage

  1. Decorator : 원래의 소스를 감싸는 방식으로 인터페이스에 동적으로 기능을 추가한다.
  2. Delegation : 상속을 통한 조합
  3. Facade : 단순화된 인터페이스 제공

클래스 다이어그램

Adapter 패턴(김동석)

소스

  1. adapter : LightningToMicroUsbAdapter.java
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    package net.dskim.desingpattern.adapter;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class LightningToMicroUsbAdapter implements MicroUsbPhone {
    	private final LightningPhone lightningPhone;
    
    	public LightningToMicroUsbAdapter(LightningPhone lightningPhone) {
    		this.lightningPhone = lightningPhone;
    	}
    
    	@Override
    	public void useMicroUsb() {
    		log.info("MicroUsb connected");
    		lightningPhone.useLightning();
    	}
    
    	@Override
    	public String recharge() {
    		return lightningPhone.recharge();
    	}
    }
  2. adaptee : LightningPhone.java
    1
    2
    3
    4
    5
    6
    
    package net.dskim.desingpattern.adapter;
    
    public interface LightningPhone {
    	String recharge();
    	void useLightning();
    }
  3. target : MicroUsbPhone.java
    1
    2
    3
    4
    5
    6
    
    package net.dskim.desingpattern.adapter;
    
    public interface MicroUsbPhone {
    	String recharge();
    	void useMicroUsb();
    }
  4. 클라이언트 : LightningToMicroUsbAdapterTest.java
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    package net.dskim.desingpattern.adapter;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    import org.junit.jupiter.api.Test;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class LightningToMicroUsbAdapterTest {
    	// MicroUsbPhone 충전전용 메소드를 반드시 써야 한다고 가정한다.
    	public String rechargeMicroUsbPhone(MicroUsbPhone microUsbPhone) {
    		microUsbPhone.useMicroUsb();
    		return microUsbPhone.recharge();
    	}
    
    	@Test
    	public void lightningToMicroUsbAdapterTest() {
            Android android = new Android();
    		String androidRechargeResult = rechargeMicroUsbPhone(android);
    		log.info("androidRechargeResult={}", androidRechargeResult);
    		assertEquals("Recharge finished", androidRechargeResult);
    
            Iphone iPhone = new Iphone();
    		//rechargeMicroUsbPhone(iPhone); //iPhone에서 micro usb를 쓰려한다면 compile 에러 발생
    		String iphoneWithMicroUsbRechargeResult = rechargeMicroUsbPhone(new LightningToMicroUsbAdapter(iPhone));
    		log.info("iphoneWithMicroUsbRechargeResult={}", iphoneWithMicroUsbRechargeResult);
    		assertEquals("Recharge finished", iphoneWithMicroUsbRechargeResult);
    	}
    }

참고