책너두 (헤드 퍼스트 디자인 패턴) 22일차 (~304p)

요약

  • 어댑터 패턴과 퍼사드 패턴
    • 퍼사드 작동 원리 알아보기
    • 홈시어터 퍼사드 만들기
      • 단순화된 인터페이스 만들기
      • 편한 방법으로 영화 보기
    • 퍼사드 패턴의 정의
    • 최소 지식 원칙
      • 친구를 만들지 않고 다른 객체에 영향력 행사하기
      • 절친에게만 메소드 호출하기

메모

퍼사드 작동 원리 알아보기

  • 쓰기 쉬운 인터페이스를 제공하는 퍼사드 클래스를 구현하면 복잡한 시스템을 훨씬 편리하게 사용할 수 있음.
    • 물론, 복잡한 시스템을 직접 건드리고 싶다면 기존 인터페이스를 그대로 쓰면 됨.
  1. 홈시어터 시스템용 퍼사드를 만든다.
    1. watchMovie() 와 같은 몇가지 간단한 메소드만 들어있는 HomeTheaterFacade 클래스를 새로만들어야 함.
  2. 퍼사드 클래스는 홈시어터 구성 요소를 하나의 서브시스템으로 간주하고 watchMovie() 메소드는 서브시스템의 메소드를 호출해서 필요한 작업을 처리함.
  3. 클라이언트 코드는 서브시스템이 아닌 홈시어터 퍼사드에 있는 메소드인 watchMovie() 메소드를 호출함.
    1. 조명, 스트리밍 플레이어, 프로젝터, 앰프, 스크린, 팝콘 기계 등이 알아서 준비됨.
  4. 퍼사드를 쓰더라도 서브시스템에 여전히 접근할 수 있음.
    1. 퍼사드 클래스는 서브시스템 클래스를 캡슐화 하지 않음.
    2. 즉, 서브시스템 클래스의 고급 기능이 필요하다면 언제든 쓸 수 있음.

홈시어터 퍼사드 만들기

public class HomeTheaterFacade {
    Amplifier amp;
    Tuner tuner;
    StreamingPlayer player;
    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;
    }

    // 기타 메소드
}
  • 퍼사드에서 서브시스템에 있는 모든 구성 요소에 접근할 수 있도록 구성해야 함.
  • 우리가 사용하고자 하는 서브시스템의 모든 구성요소가 인스턴스 변수 형태로 저장됨.
  • 퍼사드 생성자에는 서브시스템 구성요소의 레퍼런스가 전달됨.

단순화된 인터페이스 만들기

public void watch Movie (String movie) {
    System.out.println("영화 볼 준비 중"):
    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);
}

public void endMovie() {
    System.out.println("홈시어터를 끄는 중");
    popper.off();
    lights.on();
    screen.up();
    projector.off();
    amp.off();
    player.stop();
    player.off();
}
  • 서브시스템 구성 요소를 모두 합쳐서 통합 인터페이스를 만들어야 함.
    • 영화를 볼 때 사용하는 watchMovie 메소드와 영화가 끝난 후 사용하는 endMovie 메소드를 구현한다.
  • watchMove 메소드는 일일이 수동으로 했던 작업을 순서대로 처리함.
    • 각각의 작업은 서브시스템에 들어있는 구성 요소에게 위임함.
  • endMovie 메소드는 모든 구성요소를 끄는 기능을 제공함.
    • 각각의 작업은 watchMove 메소드와 마찬가지로 서브시스템에 들어있는 구성 요소에게 위임함.

편한 방법으로 영화 보기

public class HomeTheaterTestDrive {
    public static void main(String[] args) {
        // 구성 요소 초기화

        HomeTheaterFacade homeTheater =
            new HomeTheaterFacade (amp, tuner, player,
                    projector, screen, lights, popper);

        homeTheater.watchMovie("인디아나 존스:레이더스");
        homeTheater.endMovie();
    }
}
  • 단순화된 인터페이스인 HomeTHeaterFacade를 써서 영화 재생을 시작하고 홈시어터를 끌 수 있음.

퍼사드 패턴의 정의

📍 퍼사드 패턴(Facade Pattern) : 서브시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어 줌. 또, 고수준 인터페이스도 정의하므로 서브시스템을 더 편리하게 상요할 수 있음.
  • 다른 패턴과 달리 퍼사드 패턴은 복잡한 추상화 같은게 없어서 상당히 단순함.

 

  • 클라이언트는 퍼사드 덕분에 일하기 쉬워짐.
  • 퍼사드는 복잡한 서브시스템을 사용하기 편리하게 만든 통합 인터페이스임.

최소 지식 원칙

  • 새로운 객체지향 원칙임.
  • 최소 지식 원칙(Principle of Least Knowledge) : 객체 사시에 상호작용은 될 수 있으면 아주 가까운 ‘친구’ 사이에만 허용하는 편이 좋다.
📍 디자인 원칙 : 진짜 절친에게만 이야기해야 한다.
  • 시스템을 디자인할 때, 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수와 상호작용 방식에 주의를 기울여야 함.
  • 이 원칙을 잘 따르면 여러 클래스가 복잡하게 얽혀 있어서 시스템의 한 부분을 변경했을 때 다른 부분까지 줄줄이 고쳐야 하는 상황을 미리 방지할 수 있음.

친구를 만들지 않고 다른 객체에 영향력 행사하기

  • 여러 객체와 친구가 되는 것을 피할 수 있는 방법은?
  • 4가지 가이드라인을 제시함.
    • 객체 자체
    • 메소드에 매개변수로 전달된 객체
    • 메소드를 생성하거나 인스턴스를 만든 객체
    • 객체에 속하는 구성 요소
public float getTemp() {
    Thermometer thermometer = station.getThermometer();
    return thermometer.getTemperature();
}
  • 원칙을 따르지 않은 경우
    • station 으로부터 thermometer 객체를 받아서 그 객체의 getTemperature 메소드를 호출하고 있음.
public float getTemp() {
    return station.getTemperature();
}
  • 원칙을 따르는 경우
    • thermometer 에게 요청을 전달하는 메소드를 station 클래스에 추가함.
      • 의존해야 하는 클래스 개수를 줄일 수 있음.

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

public class Car {
    Engine engine;
    // 기타 인스턴스 변수

    public Car() {
        // 엔진 초기화 등을 처리
    }

    public void start(Key key) {K
        Doors doors = new Doors();
        boolean authorized = key.turns();
        if (authorized) {
            engine.start();
            updateDashboardDisplay();
            doors.lock();
        }
    }

    public void updateDashboardDisplay() {
        // 디스플레이 갱신
    }
}
  • Car 클래스의 구성요소인 Engine의 메소드는 호출해도 됨.
  • start 메소드에서 Door 객체를 새로 생성함.
    • 이 객체의 메소드는 호출해도 됨.
  • 매개변수로 전달된 Key 객체의 메소드는 호출해도 됨.
  • 객체 내에 있는 updateDashboardDisplay 메소드는 호출해도 됨.

댓글

Designed by JB FACTORY