어댑터. 틀에 따라 만들어라!
다른 개발자랑 같이 개발할 때,
다른 개발자가 뭘 만들지는 아는데 어떻게 만들지는 모를때
어댑터를 만들어주면서 이 틀에 맞춰서 만들어 달라고 한다.
자바의 mouselistener 인터페이스 와
BufferedReader, InputStreamReader, InputStream 사용할 때의
그 구조도 어댑터 패턴이라고 한다.
외부 라이브러리를 사용할때,
OCP를 위반하니까 기존 소스코드는 뜯어고칠 수 없다
그럴땐 어댑터를 만들자

발전소에서 220v로 보내는 전기를 어댑터를 통해 컴퓨터에 5v로 공급 하는 것처럼
외부에서 만든 외부호랑이를 호랑이어댑터를 통해서 doorman에게 친숙한 호랑이로
만들어서 쫓아내도록 한다.
토끼로 바꿔서 해봄
다른 사람이 만든 외부토끼 (OutterRabbit)를 라이브러리라고 보고 lib 패키지 안에 만들어준다.

package ex03.lib;
public class OuterRabbbit {
// 다른 사람이 만든 토끼
// 우리가 extends 해서 만든게 아니기 때문에 getName이 없다..!
private String fullname = "토끼";
public String getFullname() {
return fullname;
}
}
다른 사람이 만들었기 때문에 기존에 우리가 만들던 것처럼
변수 이름을 name으로 하지 않고, fullname으로 지어놨다.
이름을 꺼내는 매서드도 getName이 아닌 getFullname으로 만들어놨다.
이걸 우리 App에서 doorman한테 시키면 외부토끼 이름을 모른다.
(→ OutterRabiit이 추상화를 안했기 때문에)
이럴때 Adaptor가 필요하다

외부토끼를 위한 RabbitAdaptor를 만들었다.
(편의상 RabbitAdaptor로 이름 지은거지 Rabbit으로 지어도 된다.
그래야 Animal 상속받는게 좀 더 자연스럽게 느껴질듯?)
package ex03;
import ex03.lib.OuterRabbbit;
public class RabbitAdaptor extends Animal{
//상속이 아닌 composition으로 outerRabbit을 넣는다..
private OuterRabbbit rabbit; // 진짜 rabbit
public RabbitAdaptor(OuterRabbbit rabbit) {
this.rabbit = rabbit;
}
@Override
String getName() {
return rabbit.getFullname();
}
}
OuterRabbit 이 RabbitAdaptor의 부모가 아니니 상속이 아닌 컴포지션(composition)으로 넣어준다.
토끼어댑터는 Animal을 상속받고, getName을 오버라이드 한 뒤에
외부토끼의 이름을 return 한다. 이러면 getName 매서드만 아는 문지기가
외부토끼의 이름을 알 수 있게 된다.
package ex03;
import ex03.lib.OuterRabbbit;
/**
* Animal 생성 (abstract)
* 타입 일치(다형성) = 쥐(동물), 호랑이(동물)
* 문지기한테 dip만 지켜주면 됨
*/
public class App {
public static void main(String[] args) {
Mouse m1 = new Mouse();
Tiger t1 = new Tiger();
Doorman doorman = new Doorman();
doorman.쫓아내(m1);
RabbitAdaptor rabbit = new RabbitAdaptor(new OuterRabbbit());
// 추가기능이 아닌 호환을 위해 만든 클래스는 어댑터 패턴을 적용한것
// 추가기능을 위해 클래스를 만들어 적용하면 프록시 패턴
// 처음에는 구분이 어려운데 많이 쳐보고 실력이 쌓이면 구분할수있다.
// 기존 라이브러리를 뜯어고칠 수 없으면 어댑터를 만들어서 사용한다!
doorman.쫓아내(rabbit); // 토끼 쫓아내 성공
}
}
외부토끼를 토끼어댑터에 넣어서 문지기가 알 수 있게 바꿔주고 쫓아내라고 시키면
잘 된다.
어댑터 패턴이 프록시 패턴이랑 비슷한 느낌인데
‘호환성’을 위해 클래스를 만들어서 적용하면 → 어댑터 패턴
‘추가기능’을 위해 클래스를 만들어서 적용하면 → 프록시 패턴
이렇게 구분할 수 있다.
추가로, 디폴트 인터페이스에 대해서 배웠다.
기존에는 인터페이스에 생성된 매서드를 상속 받을 때, 모든
매서드를 상속받게 된다. 필요한 매서드만 구현하기 위해
사용할 일 없는 매서드는 adaptor 를 만들어 모든 매서드를 가지고 있는 인터페이스를 implements한 뒤에 거기서 필요없는 매서드를 구현하게 하고, 나는 이 adaptor를 상속받아서 필요한 매서드만 구현하면 된다.
이게 귀찮고 복잡해서 default 를 사용한 디폴트 인터페이스가 나왔다. 인터페이스의 매서드에 default를 달아주면, 나는 adaptor에서 필요없는 매서드를 구현하고 상속받을 필요없이,
바로 필요한 매서드만 구현할 수 있게 된다.
Share article