Menu
Coddy logo textTech

인터페이스 구성

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

Go는 더 작은 인터페이스들을 조합함으로써 더 큰 인터페이스를 구축할 수 있게 해줍니다. 많은 메서드를 가진 하나의 큰 인터페이스를 정의하는 대신, 새로운 인터페이스 정의 내부에 기존 인터페이스들을 포함시킵니다.

type Reader interface {
    Read() string
}

type Writer interface {
    Write(data string)
}

// ReadWriter는 두 인터페이스를 모두 결합합니다
type ReadWriter interface {
    Reader
    Writer
}

ReadWriter 인터페이스는 이제 Read()Write() 메서드를 모두 필요로 합니다. 두 메서드를 모두 구현하는 모든 타입은 ReadWriter뿐만 아니라 ReaderWriter를 각각 개별적으로도 충족합니다.

type File struct {
    Name string
}

func (f File) Read() string       { return "file content" }
func (f File) Write(data string)  { fmt.Println("Writing:", data) }

func Process(rw ReadWriter) {
    content := rw.Read()
    rw.Write(content)
}

func main() {
    f := File{Name: "data.txt"}
    Process(f)  // File은 ReadWriter를 충족합니다
}

이러한 구성 방식은 인터페이스를 작고 집중된 상태로 유지합니다. 필요에 따라 이들을 조합하여 함수를 위한 정밀한 계약을 만들 수 있습니다. Go의 표준 라이브러리는 io.Readerio.Writer를 결합한 io.ReadWriter와 같이 이 패턴을 광범위하게 사용합니다.

challenge icon

챌린지

쉬움

인터페이스 구성을 보여주는 미디어 플레이어 시스템을 구축해 보겠습니다. 작고 집중된 인터페이스를 만든 다음, 이를 결합하여 단일 타입이 충족할 수 있는 더 강력한 구성 인터페이스를 만들 것입니다.

코드는 두 개의 파일로 구성됩니다:

  • media.go: 세 개의 인터페이스와 이를 모두 구현하는 구조체를 정의합니다:
    • Play() string 메서드를 가진 Player 인터페이스
    • Record(content string) string 메서드를 가진 Recorder 인터페이스
    • PlayerRecorder를 모두 포함하는 MediaDevice 인터페이스
    • 모든 필수 메서드를 구현하고 Name 필드를 가진 SmartDevice 구조체
  • main.go: 동일한 SmartDevice가 서로 다른 인터페이스 타입을 통해 어떻게 사용될 수 있는지 보여주는 함수들을 만듭니다. 세 개의 함수를 작성하세요:
    • Player를 인자로 받아 Play 메서드를 호출하는 UsePlayer
    • Recorder와 콘텐츠 문자열을 인자로 받아 Record를 호출하는 UseRecorder
    • MediaDevice와 콘텐츠 문자열을 인자로 받아 RecordPlay를 모두 호출하는 UseMediaDevice
    입력에서 장치 이름과 콘텐츠를 읽고, SmartDevice를 생성한 다음, 세 가지 인터페이스 타입을 모두 사용하여 시연하십시오.

다음 입력이 제공됩니다:

  • 1행: 장치 이름
  • 2행: 녹음할 콘텐츠

메서드는 다음 형식의 문자열을 반환해야 합니다:

  • Play(): [Name] is playing
  • Record(content): [Name] recorded: [content]

예를 들어, MyPhonevoice memo가 주어지면 출력은 다음과 같아야 합니다:

MyPhone is playing
MyPhone recorded: voice memo
MyPhone recorded: voice memo
MyPhone is playing

처음 두 줄은 개별 인터페이스(PlayerRecorder)를 통해 사용된 장치를 보여줍니다. 마지막 두 줄은 두 가지 기능이 모두 필요한 구성된 MediaDevice 인터페이스를 통해 사용된 것을 보여줍니다. 단일 SmartDevice가 필요한 두 메서드를 모두 가지고 있기 때문에 세 가지 인터페이스를 모두 충족하는 방식에 주목하십시오.

치트 시트

Go는 기존 인터페이스를 새로운 인터페이스 정의 내에 포함시켜 작은 인터페이스들을 조합(composing)함으로써 더 큰 인터페이스를 구축할 수 있게 해줍니다.

type Reader interface {
    Read() string
}

type Writer interface {
    Write(data string)
}

// ReadWriter는 두 인터페이스를 모두 결합합니다
type ReadWriter interface {
    Reader
    Writer
}

포함된 인터페이스의 모든 메서드를 구현하는 모든 타입은 조합된 인터페이스를 충족합니다.

type File struct {
    Name string
}

func (f File) Read() string       { return "file content" }
func (f File) Write(data string)  { fmt.Println("Writing:", data) }

func Process(rw ReadWriter) {
    content := rw.Read()
    rw.Write(content)
}

func main() {
    f := File{Name: "data.txt"}
    Process(f)  // File은 ReadWriter를 충족합니다
}

조합된 인터페이스를 구현하는 타입은 각각의 개별 포함 인터페이스도 충족합니다. 이러한 조합 방식은 인터페이스를 작고 집중된 상태로 유지하면서 함수에 대한 정밀한 규약(contract)을 생성할 수 있게 해줍니다.

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
)

// TODO: Player를 받아 Play 메서드를 호출하는 UsePlayer를 구현하세요
// Play()의 결과를 출력해야 합니다

// TODO: Recorder와 content 문자열을 받아 UseRecorder를 구현하세요
// Record(content)의 결과를 출력해야 합니다

// TODO: MediaDevice와 content 문자열을 받는 UseMediaDevice를 구현하세요
// Record(content)의 결과를 출력한 다음 Play()를 호출해야 합니다

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	scanner.Scan()
	deviceName := scanner.Text()
	
	scanner.Scan()
	content := scanner.Text()
	
	// TODO: 주어진 이름으로 SmartDevice를 생성하세요
	
	// TODO: Player 인터페이스를 통해 장치를 사용하세요
	
	// TODO: Recorder 인터페이스를 통해 장치를 사용하세요
	
	// TODO: MediaDevice 인터페이스를 통해 장치를 사용하세요
	
	_ = deviceName
	_ = content
	fmt.Println("Implement the solution")
}
quiz icon실력 점검

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

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