Menu
Coddy logo textTech

어댑터 패턴

Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 92번째.

Adapter 패턴은 기존 타입을 새로운 인터페이스로 감싸 호환되지 않는 인터페이스들이 함께 작동하도록 합니다. Command가 작업을 캡슐화하는 반면, Adapter는 한 인터페이스를 클라이언트가 기대하는 다른 인터페이스로 변환합니다.

application이 기대하는 것과 다른 method signature를 사용하는 legacy printer가 있다고 상상해 보세요:

// 애플리케이션이 사용하는 대상 인터페이스
type Printer interface {
    Print(text string) string
}

// 호환되지 않는 인터페이스를 가진 레거시 프린터
type OldPrinter struct{}

func (o OldPrinter) PrintDocument(doc string, copies int) string {
    return fmt.Sprintf("Old printer: %s (x%d)", doc, copies)
}

어댑터는 레거시 타입을 감싸고 예상되는 인터페이스를 구현합니다:

type OldPrinterAdapter struct {
    oldPrinter OldPrinter
}

func (a OldPrinterAdapter) Print(text string) string {
    return a.oldPrinter.PrintDocument(text, 1)
}

이제 레거시 프린터가 Printer 인터페이스를 기대하는 코드와 원활하게 작동합니다:

func PrintMessage(p Printer, msg string) string {
    return p.Print(msg)
}

adapter := OldPrinterAdapter{oldPrinter: OldPrinter{}}
result := PrintMessage(adapter, "Hello")  // "Old printer: Hello (x1)"

어댑터 패턴은 서드파티 라이브러리를 통합하거나, legacy 코드와 작업하거나, interface 요구 사항과 일치하지 않는 기존 클래스를 사용해야 할 때 매우 유용합니다. 원본 코드를 수정하지 않고 브리지 역할을 합니다.

challenge icon

챌린지

쉬움

Adapter 패턴을 사용하여 미디어 플레이어 시스템을 만들어 봅시다! 통합된 인터페이스를 필요로 하는 최신 오디오 플레이어가 있지만, 메서드 시그니처가 완전히 다른 레거시 오디오 장비를 통합해야 합니다. adapter가 이 간극을 연결하여 기존 하드웨어가 새 시스템과 원활하게 작동하도록 합니다.

코드를 세 개의 파일로 구성합니다:

  • player.go: 대상 인터페이스와 레거시 오디오 장치를 정의합니다.

    최신 시스템이 필요로 하는 AudioPlayer 인터페이스를 만듭니다. 이 인터페이스에는 트랙 이름을 받고 재생 메시지를 반환하는 Play(track string) string 메서드가 있어야 합니다.

    또한 이 인터페이스와 일치하지 않는 레거시 장치를 정의합니다:

    • VinylPlayer 구조체에 SpeedRPM 필드(int)를 추가합니다. 이 구조체에는 DropNeedle(record string, side string) string 메서드가 있으며, Playing [record] ([side] side) at [speed]rpm을 반환합니다.

    VinylPlayer의 인터페이스는 AudioPlayer와 호환되지 않습니다. 두 개의 매개변수가 필요하고 완전히 다른 메서드 이름을 사용합니다.

  • adapter.go: 레거시 장치를 호환 가능하게 만드는 adapter를 생성합니다.

    VinylPlayer를 감싸고 AudioPlayer 인터페이스를 구현하는 VinylAdapter 구조체를 만듭니다. Play가 호출되면 adapter는 바이닐 플레이어의 DropNeedle 메서드를 호출하며, side 매개변수에는 기본값으로 A를 사용해야 합니다.

    비교를 위해 최신 플레이어도 만듭니다:

    • DigitalPlayer 구조체: Play 메서드는 Streaming: [track]을 반환합니다.
  • main.go: 동일한 인터페이스를 통해 두 플레이어가 모두 작동하는 모습을 보여 줍니다.

    인터페이스를 사용하여 음악을 재생하는 PlayMusic(player AudioPlayer, track string) string 함수를 만듭니다. 이 함수는 디지털 플레이어를 사용하는지, adapter가 적용된 바이닐 플레이어를 사용하는지 알거나 신경 쓸 필요가 없습니다.

    플레이어 유형(digital 또는 vinyl)을 읽고, vinyl인 경우 RPM 속도도 읽습니다. 그런 다음 트랙 이름을 읽습니다. 적절한 플레이어를 생성하고(vinyl에는 adapter 사용), PlayMusic 함수를 통해 트랙을 재생한 다음 결과를 출력합니다.

다음 입력이 제공됩니다:

  • 1번째 줄: 플레이어 유형(digital 또는 vinyl)
  • 2번째 줄: RPM 속도(vinyl인 경우에만)
  • 마지막 줄: 재생할 트랙 이름

예를 들어 다음이 주어졌을 때:

digital
Bohemian Rhapsody

출력은 다음과 같아야 합니다:

Streaming: Bohemian Rhapsody

또한 다음이 주어졌을 때:

vinyl
33
Abbey Road

출력은 다음과 같아야 합니다:

Playing Abbey Road (A side) at 33rpm

또한 다음이 주어졌을 때:

vinyl
45
Blue Monday

출력은 다음과 같아야 합니다:

Playing Blue Monday (A side) at 45rpm

PlayMusic 함수가 두 플레이어 모두에서 동일하게 작동하는 것을 확인하세요. 이 함수는 바이닐 플레이어가 실제로는 완전히 다른 인터페이스에서 adapter를 통해 변환되었다는 사실을 전혀 알지 못합니다. adapter가 최신 인터페이스 호출을 내부적으로 레거시 형식으로 변환합니다!

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// PlayMusic는 AudioPlayer 인터페이스를 사용하여 음악을 재생합니다
// 이 함수는 모든 AudioPlayer 구현과 함께 작동합니다
// TODO: player.Play(track)를 호출하고 결과를 반환하도록 이 함수를 구현하세요
func PlayMusic(player AudioPlayer, track string) string {
	// TODO: 이 함수를 구현하세요
	return ""
}

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// 플레이어 유형 읽기
	playerType, _ := reader.ReadString('\n')
	playerType = strings.TrimSpace(playerType)
	
	var player AudioPlayer
	var track string
	
	if playerType == "vinyl" {
		// 비닐용 RPM 속도 읽기
		rpmStr, _ := reader.ReadString('\n')
		rpmStr = strings.TrimSpace(rpmStr)
		rpm, _ := strconv.Atoi(rpmStr)
		
		// 트랙 이름 읽기
		track, _ = reader.ReadString('\n')
		track = strings.TrimSpace(track)
		
		// TODO: 주어진 RPM으로 VinylPlayer를 생성하세요
		// TODO: VinylAdapter로 감싸세요
		// TODO: player 변수에 할당하세요
		_ = rpm // rpm을 사용할 때 이 줄을 제거하세요
	} else {
		// 트랙 이름 읽기
		track, _ = reader.ReadString('\n')
		track = strings.TrimSpace(track)
		
		// TODO: DigitalPlayer를 생성하세요
		// TODO: player 변수에 할당하세요
	}
	
	// TODO: PlayMusic을 호출하고 결과를 출력하세요
	_ = player // player를 사용할 때 이 줄을 제거하세요
	_ = track  // track을 사용할 때 이 줄을 제거하세요
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Go 컴파일러