Ch.7 어댑터 패턴과 퍼사드 패턴

적응시키기

About

이번 챕터에서는 하나의 인터페이스를 다른 인터페이스로 변환하는 두 가지 디자인 패턴을 배워본다.

  • 어댑터 패턴(Adapter Pattern) - 특정 인터페이스가 필요한 디자인을 다른 인터페이스를 구현하는 클래스에 적응시키는 패턴

  • 퍼사드 패턴(Facade Pattern) - 객체를 감싸서 인터페이스를 단순화하는 패턴

The Code

Introducing -- The "Adapter" Pattern

어댑터 패턴을 떠올릴 때는 다음 그림들을 떠올리자. (출처: Head First Design Patterns)

  • US AC 플러그를 영국식 전원 소켓에 꽂기 위해 AC 전원 어댑터를 이용한다.

  • 이를 응용해 기존 시스템에서 벤더 클래스를 사용하기 위해 어댑터 클래스를 만들 수 있다.

예를 들면, 오리가 꽥꽥(quack)거리고 날아다니는데(fly), 가금류인 칠면조는 골골(gobble)거리고 날갯짓(fly)할 수 있다.

  • 칠면조를 오리처럼 만들기 위해 가금류 어댑터(TurkeyAdapter)를 만들 수 있다.

import { Duck } from './duck'
import { Turkey } from './turkey'

export class TurkeyAdapter implements Duck {
  turkey: Turkey

  constructor(turkey: Turkey) {
    this.turkey = turkey
  }

  quack(): void {
    this.turkey.gobble()
  }

  fly(): void {
    for (let i = 0; i < 5; i++) {
      this.turkey.fly()
    }
  }
}
  • turkeyAdapter.quack()이 호출되면 turkey.gobble()을 호출하도록 했다.

  • turkeyAdapter.fly()가 호출되면 turkey.fly()를 여러 번 넣어 나는 것을 흉내냈다.

Adapter Pattern Definition

  • 어댑터 패턴(Adapter Pattern)은 특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환한다.

  • 인터페이스가 호환되지 않아 같이 쓸 수 없었던 클래스를 쉽게 사용할 수 있다.

  • 어댑터 패턴은 합성(Composition)을 통해 구현이 가능하다.

    • 클래스 어댑터를 사용해 상속으로도 구현이 가능하지만, 자바에서는 다중 상속이 불가능하기도 하고 추천하지는 않다.

Let's talk about -- The Facade Pattern

  • HomeTheaterFacadewatchMove, endMove만 이용해서 영화를 보고 끄는 것과 관련된 모든 일련의 작업을 수행할 수 있다.

Facade Pattern Definition

  • 퍼사드 패턴(Facade Pattern)은 서브시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어 준다.

  • 또한 고수준 인터페이스도 정의하므로 서브시스템을 편리하게 사용할 수 있다.

이제 이런 식으로 내부적으로 합성을 이용해 필요한 서브시스템의 메소드를 호출하면 된다.

export class HomeTheaterFacade {
  private readonly amp: Amplifier
  private readonly tuner: Tuner
  private readonly player: StreamingPlayer
  private readonly projector: Projector
  private readonly lights: TheaterLights
  private readonly screen: Screen
  private readonly popper: PopcornPopper

  constructor(
    amplifier: Amplifier,
    tuner: Tuner,
    player: StreamingPlayer,
    projector: Projector,
    lights: TheaterLights,
    screen: Screen,
    popper: PopcornPopper,
  ) {
    this.amp = amplifier
    this.tuner = tuner
    this.player = player
    this.projector = projector
    this.lights = lights
    this.screen = screen
    this.popper = popper
  }

  watchMovie(movie: string): void {
    console.log('Get ready to watch a movie...')
    this.popper.on()
    this.popper.pop()
    this.lights.dim(10)
    this.screen.down()
    this.projector.on()
    this.projector.setWideScreenMode()
    this.amp.on()
    this.amp.setStreamingPlayer(this.player)
    this.amp.setSurroundSound()
    this.amp.setVolume(5)
    this.player.on()
    this.player.play(movie)
  }

  endMovie(): void {
    console.log('Shutting movie theater down...')
    this.popper.off()
    this.lights.on()
    this.screen.up()
    this.projector.off()
    this.amp.off()
    this.player.stop()
    this.player.off()
  }
}

번외: 최소 지식 원칙 (Principle of Least Knowledge)

객체 사이의 상호작용은 될 수 있으면 아주 가까운 '친구' 사이에서만 허용하는 편이 좋다.

  • 최소 지식 원칙(Principle of Least Knowledge), 디미터의 법칙(Law of Demeter)은 동의어다.

이 원칙은 친구를 만들지 않는 4개의 가이드라인을 제시합니다.

  • 객체 자체

  • 메소드에 매개변수로 전달된 객체

  • 메소드를 생성하거나 인스턴스를 만든 객체

  • 객체에 속하는 구성 요소

Last updated