본문 바로가기
Book

[독서 기록] 헤드퍼스트 디자인 패턴 7장 | 적응시키기 - 어댑터 패턴과 퍼사드 패턴

by Renechoi 2022. 11. 15.
 
헤드 퍼스트 디자인 패턴
이유 1. 흥미로운 이야기와 재치 넘치는 구성이 담긴 〈헤드 퍼스트〉 시리즈! 하나의 패턴에 하나의 이야기를 담았습니다. 틀에 박히지 않아 지루할 틈이 없는 구성과 친구와 이야기하듯 편안한 대화체로 이야기를 풀어냅니다. 이야기 속에 다양한 방법으로 해결할 수 있는 질문과 90개 이상의 연습문제를 담았습니다. 마치 게임 퀘스트를 해결하듯 문제를 하나하나 해결하다 보면 학습한 내용이 머릿속에 강렬하게 남습니다. 이유 2. 원스톱으로 배우는 14가지 GoF 핵심 디자인 패턴과 9가지 객체지향 디자인 원칙! 현장에서 자주 사용되는 옵저버, 어댑터, MVC 패턴 등 14가지 GoF 객체지향 패턴을 중점으로 패턴의 정의, 사용 시기, 사용처, 사용 이유, 즉시 디자인에 적용하는 방법을 알려줍니다. 이와 더불어 객체지향 프로그래밍에 광범위하게 적용할 수 있는 OCP, 할리우드 원칙 등 9가지 객체지향 디자인 원칙과 패턴으로 생각하는 방법도 알려줍니다. 이유 3. 시대의 변화에 맞춘 개정과 한국 독자만을 위한 특별판! 자바 8과 자바 16 이상에서 무리 없이 동작할 수 있도록 예제 코드를 수정했으며, 부가적인 설명과 Q&A 질문을 추가했습니다. 또한 16여 년 만의 개정을 기념해 오직 한국 독자만을 위한 새로운 삽화를 사용하고 한글 친화적인 구성했습니다. 원서를 읽을 때보다 더욱 편안하게 디자인 패턴을 학습할 수 있습니다. ▶ 이 책을 읽어야 하는 당신! ● 소프트웨어 출시는 완벽 그 자체! “어?~ 코드 수정하려고 다시 보니까 난리…” → 유지보수만 생각하면 그저 눈물인 주니어 (자바) 개발자 ● 코딩 실력은 장판파의 장비! “어?~ 팩토리 메소드 패턴을 이렇게 적용했던가?” → 디자인 패턴을 다시 한번 살펴보고 싶은 시니어 (자바) 개발자 ● 혼자 공부해서 다진 프로그래밍 언어 실력! “어?~ 근데 패턴이 뭐야?” → 개발 현장의 소프트웨어 디자인 방법이 궁금한 개발자 지망생
저자
에릭 프리먼, 엘리자베스 롭슨, 케이시 시에라, 버트 베이츠
출판
한빛미디어
출판일
2022.03.16

 

헤드퍼스트 디자인 패턴 7장 | 적응시키기 - 어댑터 패턴과 퍼사드 패턴

(에릭 프리먼 외 4인, 서환수 옮김, 한빛미디어)

 


 

객체지향 어댑터도 일상생활에서 쓰이는 어댑터와 똑같은 역할을 합니다. 어떤 인터페이스를 클라이언트에서 요구하는 형태로 적응시키는 역할을 하죠.

- 272p 

 

public class TurkeyAdapter implements Duck {
	Turkey turkey;
 
	public TurkeyAdapter(Turkey turkey) {
		this.turkey = turkey;
	}
    
	public void quack() {
		turkey.gobble();
	}
  
	public void fly() {
		for(int i=0; i < 5; i++) {
			turkey.fly();
		}
	}

=> 우선 적응시킬 형식의 인터페이스를 구현해야 합니다. 다시 말해, 클라이언트에서 원하는 인터페이스를 구현해야 하죠.

=> 그리고 기존 형식 객체의 레퍼런스가 필요합니다. 여기서는 생성자에서 레퍼런스를 받아오는 작업을 처리합니다.

=> 인터페이스에 들어있는 메소드를 모두 구현해야 합니다. 

quack()은 간단합니다. 그냥 gobble() 메소드를 호출하면 되죠.

=> 두 인터페이스 모두 fly()가 들어있지만 5번 호출 => 좀 더 멀리 움직이도록 

 

- 275p

 

public class DuckTestDrive {
   public static void main(String[] args) {
      Duck duck = new MallardDuck();

      Turkey turkey = new WildTurkey();
      Duck turkeyAdapter = new TurkeyAdapter(turkey);
      => Turkey 객체를 TurkeyAdapter로 감싸서 duck 객체처럼 보이도록 만듭니다.

- 276p 

 

 

어댑터 패턴은 특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환합니다. 인터페이스가 호환되지 않아 같이 쓸 수 없었던 클래스를 사용할 수 있게 도와줍니다.

- 279p 

 


퍼사드 패턴 맛보기 

 

이제부터 조금 다른 이유로 인터페이스를 변경하는 패턴을 알아보겠습니다. 이 패턴은 인터페이스를 단순하게 바꾸려고 인터페이스를 변경하죠. 이 패턴의 이름은 퍼사드 패턴입니다. 하나 이상의 클래스 인터페이스를 깔끔하면서도 효과적인 퍼사드(facade)로 덮어 주거든요.

- 290p 

 

 

퍼사드는 인터페이스를 단순하게 만들고 클라이언트와 구성 요소로 이루어진 서브시스템을 분리하는 역할도 합니다. 퍼사드와 어댑터는 모두 여러 개의 클래스를 감쌀 수 있습니다. 하지만 퍼사드는 인터페이스를 단순하게 만드는 용도로 쓰이는 반면, 어댑터는 인터페이스를 다른 인터페이스로 변환하는 용도로 쓰입니다.

- 296p 

 

 

public class HomeTheaterFacade {
   Amplifier amp;
   Tuner tuner;
   StreamingPlayer player;
   CdPlayer cd;
   Projector projector;
   TheaterLights lights;
   Screen screen;
   PopcornPopper popper;

=> 구성 부분. 우리가 사용하고자 하는 서브시스템의 모든 구성 요소가 인스턴스 변수 형태로 저장됩니다.

   public HomeTheaterFacade(Amplifier amp, 
             Tuner tuner, 
             StreamingPlayer player, 
             Projector projector, 
             Screen screen,
             TheaterLights lights,
             PopcornPopper popper) {
             
             => 퍼사드의 생성자에는 서브시스템의 구성 요소의 레퍼런스가 전달됩니다.
             퍼사드는 각 레퍼런스를 인스턴스 변수에 저장합니다.
 
      this.amp = amp;
      this.tuner = tuner;
      this.player = player;
      this.projector = projector;
      this.screen = screen;
      this.lights = lights;
      this.popper = popper;
   }

 

watchMovie() 메소드와 영화가 끝난 후 사용하는 endMovie() 메소드를 구현 

 

public void watchMovie(String movie) {
   System.out.println("Get ready to watch a movie...");
   popper.on();
   popper.pop();
   lights.dim(10);
   screen.down();
   projector.on();
   projector.wideScreenMode();
   amp.on();
   amp.setStreamingPlayer(player);
   amp.setSurroundSound();
   amp.setVolume(5);
   player.on();
   player.play(movie);
}

=> watchMovie() 메소드는 앞에서 일일이 수동으로 했던 작업을 순서대로 처리합니다. 
꽤 복잡한 일을 하나의 메서드로 간단하게 처리할 수 있죠.
각 작업은 서비시스템에 들어있는 구성 요소에게 위임됩니다.

public void endMovie() {
   System.out.println("Shutting movie theater down...");
   popper.off();
   lights.on();
   screen.up();
   projector.off();
   amp.off();
   player.stop();
   player.off();
}

public void listenToRadio(double frequency) {

 

- 296 ~ 298p

 

 

최소 지식 원칙에 따르면 객체 사이의 상호작용은 될 수 있으면 아주 가까운 '친구' 사이에서만 허용하는 편이 좋습니다. 이 원칙은 보통 다음과 같이 정의할 수 있습니다.

 

디자인 원칙 : 진짜 절친에게만 이야기해야 한다. 

 

- 301p 

 

 

원칙을 따르지 않은 경우

public float getTemp() {
	Thermomter thermometer = station.getThermometer();
    return thermometer.getTemperature();
}

=> station으로부터 thermometer 객체를 받은 다음, 그 객체의 getTemperature() 메소드를 직접 호출합니다.

원칙을 따르는 경우

public float getTemp() {
	return station.getTemperature();
}

=> 최소 지식 원칙을 적용해서 thermometer에게
요청을 전달하는 메소드를 station 클래스에 추가했습니다.
이러면 의존해야 하는 클래스의 개수를 줄일 수 있죠.

 

- 302p

 

 

절친에게만 메소드 호출하기

 

public class Car {
	Engine engine;
    => 이 클래스의 구성 요소
    이 구성요소의 메소드는 호출해도 되죠.
    
    public Car() {
    	// 엔진 초기화 등을 처리
    }
    
    public void start(Key key) {				=> 매개 변수로 전달받은 객체의 메소드는 호출해도 됩니다.
    	Doors doors = new Doors();				=> 새로운 객체 생성 
        boolean authorized = key.turfns();		=> 매개 변수로 전달받은 객체의 메소드 
        if (authorized) {
        engine.start()				=> 객체 내의 구성 요소 호출 가능
        updateDashboardDisplay();	=> 객체 내의 메소드 호출 가능
        doors.lock();				=> 직접 생성하거나 인스턴스를 만든 객체의 메소드 호출 가능
        =
        }
     }
     
     public void updateDashBoardDisplay() {
     	// 디스플레이 갱신
    } 
 }

- 303p 

 

 

반응형