어댑터 패턴
객체지향 어댑터가 뭔지는 그리 어렵지 않게 이해할 수 있을 것이다.
흔히 미국여행 갔을 경우 어댑터가 달라서 준비해간 경험이 있다면 말이다.
어댑터의 역할은 국산 플러그와 미국식 소켓 사이에서 국산 전원 플러그를 미국식 소켓에 꽂을 수 있게 해주는 역할을 한다.
그렇다면 객체지향 어댑터는 어떨까?
객체지향 어댑터
어떤 소프트웨어 시스템이 있는데, 새로운 업체에서 제공한 클래스 라이브러리를 사용해야 한다고 해 보자. 그런데 새로 채택한 업체에서 사용하는 인터페이스가 기존 업체에서 사용하던 인터페이스하고 다르다고 가정해 보자.
하지만 기존의 코드를 바꿔서 이 문제를 해결할 수는 없는 상황이다.
그렇다고 업체에서 공급 받은 클래스도 변경할 수 없고..
그렇다면 이때 한 업체에서 사용하는 인터페이스를 기존에 사용하던 인터페이스에 적응시켜주는 클래스를 만들 수 있을 것이다.
즉 어댑터는 클라이언트로부터 요청을 받아서 새로운 업체에서 제공하는 클래스에서 받아들일 수 있는 형태의 요청으로 변환시켜주는 중개인 역할을 한다.
package adapter;
public interface Duck {
public void quack();
public void fly();
}
package adapter;
public class MallardDuck implements Duck {
@Override
public void quack() {
System.out.println("Quack");
}
@Override
public void fly() {
System.out.printf("i'm flying");
}
}
package adapter;
public interface Turkey {
public void gobble();
public void fly();
}
package adapter;
public class WildTurkey implements Turkey {
@Override
public void gobble() {
System.out.println("Gobble gobble");
}
@Override
public void fly() {
System.out.println("I'm flying a short distance");
}
}
package adapter;
public class TurkeyAdapter implements Duck {
Turkey turkey;
public TurkeyAdapter(Turkey turkey){
this.turkey = turkey;
}
@Override
public void quack() {
turkey.gobble();
}
@Override
public void fly() {
for(int i=0; i<5; i++){
turkey.fly();
}
}
}
import adapter.Duck;
import adapter.TurkeyAdapter;
import adapter.WildTurkey;
public class Main {
public static void main(String[] args) {
WildTurkey turkey = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(turkey);
turkeyAdapter.quack();
turkeyAdapter.fly();
}
}
1. 클라이언트에서 타겟 인터페이스를 사용하여 메소드를 호출합니다.
2. 어댑처에서는 어댑티 인터페이스를 사용하여 그 요청을 메소드 호출로 변환합니다.
3. 클라이언트에서는 호출 결과를 받긴 하지만 중간에 어댑터가 껴 있는지는 전혀 알지 못합니다.
특정 클라이언트를 특정 구현이 아닌 인터페이스에 연결시키면 인터페이스 기준으로 코딩을 했기 때문에 타겟 인터페이스만 제대로 지킨다면 나중에 다른 구현을 추가하는 것도 가능하다.
---
package main.adapter.service;
/**
* 상품의 배너를 만들어주는 클래스
*
*/
public class Banner {
private String string;
public Banner(String string){
this.string = string;
}
public void showWithSmall(){
System.out.println("(" + string + ")");
}
public void showWithLarge(){
System.out.println("{" + string + "}");
}
}
package main.adapter.service;
public interface Printable {
void printWeak();
void printStrong();
}
package main.adapter.service;
public class PrintableBannerAdapter implements Printable {
private Banner banner;
PrintableBannerAdapter(String string){
this.banner = new Banner(string);
}
@Override
public void printWeak() {
banner.showWithSmall();
}
@Override
public void printStrong() {
banner.showWithLarge();
}
}
만약 기존에 사용하던 Banner 가 버그도 없고 최대한 재이용하고 싶은 경우가 있다면 ?
새로 만드는 클래스에서 어댑터를 만든 뒤에 부품으로 재이용하면 된다.
package main.adapter.service;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* 어뎁터를 맞춰 낄 수 있다.
*
* 다른 어뎁터가 있다면 다른 어뎁터로 바꿔끼면 된다.
*/
public class PrintableBannerAdapterTest {
@Test
public void printWeak() {
Printable p = new PrintableBannerAdapter("test");
p.printWeak();
}
@Test
public void printStrong() {
Printable p = new PrintableBannerAdapter("test2");
p.printStrong();
}
}
'개발 > java' 카테고리의 다른 글
java 복잡한 Comparator 예제 (0) | 2019.12.19 |
---|---|
템플릿 메소드 패턴 (2) | 2019.07.04 |
커맨드 패턴 (0) | 2019.06.30 |
자바 날짜계산 유틸리티 구현 (0) | 2019.02.19 |
java Ramda 리스트 컬랙션 데이터 예제 (0) | 2019.01.30 |
댓글