어댑터 패턴(Adapter Pattern)
![](https://blog.kakaocdn.net/dn/BRurT/btrTaOzwWbk/Kk3HhzxG5Kb9uepk6wsw1k/img.png)
데코레이터 패턴이 기억나시나요? 객체를 래퍼로 감싸서 새로운 역할을 부여했습니다.
StarBeverage beverage = new Americano();
beverage = new Ice(beverage); //이런식으로 말이죠!
어댑터 패턴은 조금 다릅니다.!
이번에는 실제와 다른 인터페이스를 가진 것처럼 보이도록 객체를 감싸겠습니다.
어댑터 패턴을 사용하면 특정 인터페이스가 필요한 디자인을 다른 인터페이스를 구현하는 클래스에 적응시킬 수 있습니다.
어댑터 패턴은 특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환합니다. 인터페이스가 호환되지 않아 같이 사용할 수 없었던 클래스를 사용할 수 있게 도와줍니다.
어댑터 패턴 구조
어댑터 패턴은 2가지로 구성됩니다.
객체 어댑터
구성(Composition
)을 사용하여 동작을 구현 합니다.
어댑티의 모든 서브클래스에 어댑터를 사용할 수 있다는 장점이 있습니다.
![](https://blog.kakaocdn.net/dn/zDUja/btrS6ZBTQQj/Un6YHqk2ERbIRRmVMqIwOk/img.png)
클래스 어댑터
상속을 사용하여 동작을 구현 합니다.
![](https://blog.kakaocdn.net/dn/rIXYu/btrTbUFIGtQ/KARtHbyVynrOGGjTyNo0wK/img.png)
- Target
- 클라이언트가 요구하는 타깃
- Adapter
- 어댑터에서 타킷 인터페이스를 구현 합니다.
- Adaptee
- 모든 요청은 어댑터에 위임
라인프렌즈 브라운이 라이언으로 분장하기
![](https://blog.kakaocdn.net/dn/bOYKqY/btrTaC0nOVG/m0R2Ksj8rZKBh7l0lRAJ31/img.png)
라인프렌즈의 브라운이 카카오 아지토에 놀러갔습니다.
이때 브라운이 카카오프렌즈를 놀래키기 위해서 라이언으로 분장하려고 합니다.!
방금 배운 어댑터 패턴을 사용해서 브라운을 도와줘 볼까요?
![](https://blog.kakaocdn.net/dn/dkdV80/btrTaKqbZrI/PwCIXnwKvwriymaurv9hN1/img.png)
KakaoFriends
public interface KakaoFirends {
void hello();
void action();
}
Ryan
public class Ryan implements KakaoFirends {
@Override
public void hello() {
System.out.println("나는 라이언 입니다.");
}
@Override
public void action() {
System.out.println("라이언은 따봉을 했습니다.");
}
}
LineFriends
public interface LineFriends {
void hi();
void dance();
}
Brown
public class Brown implements LineFriends {
@Override
public void hi() {
System.out.println("안녕 나는 브라운이야!");
}
@Override
public void dance() {
System.out.println("춤신춤왕 브라운!");
}
}
BrownAdapter
public class BrownAdapter implements KakaoFirends {
private LineFriends lineFriends;
public BrownAdapter(LineFriends lineFriends) {
this.lineFriends = lineFriends;
}
@Override
public void hello() {
lineFriends.hi();
System.out.println("아닙니다. 브..라이언 입니다.!");
}
@Override
public void action() {
lineFriends.dance();
System.out.println("아닙니다. 브..라이언 입니다.!");
}
}
KakaoFriends
public class Client {
public static void main(String[] args) {
KakaoFirends ryan = new Ryan();
LineFriends brown = new Brown();
//브라운이 카카오프렌즈 소속으로 바꼈습니다..!
KakaoFirends brownAdapter = new BrownAdapter(brown);
ryan.hello();
ryan.action();
System.out.println("=======================");
brown.hi();
brown.dance();
System.out.println("=======================");
brownAdapter.hello();
brownAdapter.action();
System.out.println("=======================");
System.out.println("ryan instanceof KakaoFirends ? "+(ryan instanceof KakaoFirends));
System.out.println("brown instanceof KakaoFirends ? "+(brown instanceof KakaoFirends));
System.out.println("brownAdapter instanceof KakaoFirends ? "+(brownAdapter instanceof KakaoFirends));
}
}
결과
나는 라이언 입니다.
라이언은 따봉을 했습니다.
=======================
안녕 나는 브라운이야!
춤신춤왕 브라운!
=======================
안녕 나는 브라운이야!
아닙니다. 브..라이언 입니다.!
춤신춤왕 브라운!
아닙니다. 브..라이언 입니다.!
=======================
ryan instanceof KakaoFirends ? true
brown instanceof KakaoFirends ? false
brownAdapter instanceof KakaoFirends ? true
퍼사드 패턴(Facade Pattern)
![](https://blog.kakaocdn.net/dn/cr2scP/btrTckRILmz/0QNhzkuKEmN7ZZj6ScXYB1/img.png)
인터페이스를 단순하게 바꾸려고 인터페이스를 변경하는 패턴
서브시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어 줍니다.
고수준 인터페이스도 정의하므로 서브시스템을 더 편리하게 사용할 수 있습니다.
앞에서 배운 어댑터 패턴은 인터페이스를 반환하고, 퍼사드 패턴은 단순하게 인터페이스를 통합 합니다.
퍼사드 패턴 구조
![](https://blog.kakaocdn.net/dn/cEKG1S/btrS6YbVG6g/sMPNpOLMxjXl0G91JVGoK0/img.png)
무슨말인지 잘 모르겠다구요?
음…
예를 들어서 다음과 같은 시스템이 있다고 합시다.
당신의 집은 스마트홈시스템이 적용되어 있습니다.
그래서 몇가지 패턴을 적용했습니다.
- 아침 8시가 되면 알람이 울린다.
- 커튼이 열립니다.
- 어제 내렸던 스크린이 올라갑니다.
- 조명도 켜집니다.
- 조명 밝기는 최대로~
- 그리고 플레이리스트에 있는 음악이 흘러나옵니다.
이걸 코드로 나타내 볼까요?
alarm.on();
curtain.open();
screen.up();
light.on();
light.dim(100);
musicPlayer.play();
//클래스가 5개나 필요합니다!!
그런데 당신이 출근하고 집을 비우면 어떻게 해야할까요?
방금 했던 동작을 모두 종료해야 하지 않을까요?
😖 으.. 너무 복잡하군요…
이러한 복잡한 과정을 사용하기 퍼사드 클래스를 구현함으로써 복잡한 시스템을 훨씬 편리하게 사용할 수 있습니다.!
public class HomeSystem {
Alaram alaram;
Curtain curtain;
Screen screen;
Light light;
MusicPlayer musicPlayer;
public GoodMorningHomeSystem(Alaram alaram, Curtain curtain, Screen screen, Light light, MusicPlayer musicPlayer) {
this.alaram = alaram;
this.curtain = curtain;
this.screen = screen;
this.light = light;
this.musicPlayer = musicPlayer;
}
public void GoodMorning() {
System.out.println("아침모드 동작");
alarm.on();
curtain.open();
screen.up();
light.on();
light.dim(100);
musicPlayer.play();
}
}
퍼사드 패턴을 사용하려면 어떤 서브시스템에 속한 일련의 복잡한 클래스를 단순하게 바꿔서 통합한 클래스를 만들어야 합니다.^^
퍼사드 패턴을 사용하면 클라이언트와 서브시스템이 서로 긴밀하게 연결되지 않아도 됩니다.
퍼사드 패턴은 단순화된 인터페이스로 서브시스템을 더 편리하게 사용하려고 사용된 것을 알 수 있습니다.
최소 지식 원칙(Principle of Least Knowledge)
결합도가 낮은 설계를 위한 원칙입니다…!!
최소 지식 원칙에 따르면 객체 사이의 상호작용은 될 수 있으면
아주 가까운 친구
사이에만 허용하는 편이 좋습니다.!
진짜 절친한테만 이야기하세요!
이말은 시스템을 디자인할 때 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수와 상호작용 방식에 주의를 기울여야한다는 의미 입니다.!
최소 지식 원칙을 잘 지키면 여러 클래스가 복잡하게 얽혀 있어, 시스템의 한 부분을 수정 했을 때 다른 부분까지 수정하는 상황을 예방합니다.
여러 객체와 친구가 되는 것을 피할수 있는 최소 지식 원칙 가이드 라인
모든 종류의 메소드는 가이드라인에 해당하는 메소드들로만 호출이 가능합니다.^^
- 객체 자체
- 메소드에 매개변수로 전달된 객체
- 메소드를 생성하거나 인스턴스를 만든 객체
- 객체에 속하는 구성 요소
원칙을 따르지 않는 경우
station
, themometer
에 의존하고 있습니다.
public int getTemp() {
Themometer themometer = station.getTemperature();
return themometer.getTemperature();
}
원칙을 준수한 경우
themometer
에게 요청을 전달하는 메소드를 Station
클래스에 추가 했습니다.
이러면 의존해야하는 클래스의 갯수를 줄일 수 있습니다.station
에만 의존하고 있습니다.
public int getTemp() {
return station.getTemperature();
}
정리
- 어댑터 패턴은 객체를 감싸서 인터페이스를 바꾸고 반환하는 용도로 사용합니다.
- 데코레이터 패턴은 객체를 감싸서 새로운 행동을 추가하는 용도로 사용합니다.
- 퍼사드 패턴은 일련의 객체를 감싸서 단순하게 만드는 용도로 사용합니다.
'컴퓨터과학 > 0 + 소프트웨어 아키텍처(디자인 패턴)' 카테고리의 다른 글
[소프트웨어 아키텍처] 16. 브릿지 패턴(Bridge Pattern -java) (0) | 2022.12.09 |
---|---|
[소프트웨어 아키텍처] 14. 데코레이터 패턴(Decorator Pattern -java) (0) | 2022.12.07 |
[소프트웨어 아키텍처] 13. 프로토타입 패턴(Prototype Pattern -java) (0) | 2022.12.07 |
[소프트웨어 아키텍처] 12. 빌더 패턴(Builder Pattern -java) (0) | 2022.12.06 |
[소프트웨어 아키텍처] 11. 싱글톤 패턴(Singleton Pattern -java) (0) | 2022.12.06 |