인터페이스 구성
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뿐만 아니라 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를 충족합니다
}이러한 구성 방식은 인터페이스를 작고 집중된 상태로 유지합니다. 필요에 따라 이들을 조합하여 함수를 위한 정밀한 계약을 만들 수 있습니다. Go의 표준 라이브러리는 io.Reader와 io.Writer를 결합한 io.ReadWriter와 같이 이 패턴을 광범위하게 사용합니다.
챌린지
쉬움인터페이스 구성을 보여주는 미디어 플레이어 시스템을 구축해 보겠습니다. 작고 집중된 인터페이스를 만든 다음, 이를 결합하여 단일 타입이 충족할 수 있는 더 강력한 구성 인터페이스를 만들 것입니다.
코드는 두 개의 파일로 구성됩니다:
media.go: 세 개의 인터페이스와 이를 모두 구현하는 구조체를 정의합니다:Play() string메서드를 가진Player인터페이스Record(content string) string메서드를 가진Recorder인터페이스Player와Recorder를 모두 포함하는MediaDevice인터페이스- 모든 필수 메서드를 구현하고
Name필드를 가진SmartDevice구조체
main.go: 동일한SmartDevice가 서로 다른 인터페이스 타입을 통해 어떻게 사용될 수 있는지 보여주는 함수들을 만듭니다. 세 개의 함수를 작성하세요:Player를 인자로 받아Play메서드를 호출하는UsePlayerRecorder와 콘텐츠 문자열을 인자로 받아Record를 호출하는UseRecorderMediaDevice와 콘텐츠 문자열을 인자로 받아Record와Play를 모두 호출하는UseMediaDevice
SmartDevice를 생성한 다음, 세 가지 인터페이스 타입을 모두 사용하여 시연하십시오.
다음 입력이 제공됩니다:
- 1행: 장치 이름
- 2행: 녹음할 콘텐츠
메서드는 다음 형식의 문자열을 반환해야 합니다:
Play():[Name] is playingRecord(content):[Name] recorded: [content]
예를 들어, MyPhone과 voice memo가 주어지면 출력은 다음과 같아야 합니다:
MyPhone is playing
MyPhone recorded: voice memo
MyPhone recorded: voice memo
MyPhone is playing처음 두 줄은 개별 인터페이스(Player 및 Recorder)를 통해 사용된 장치를 보여줍니다. 마지막 두 줄은 두 가지 기능이 모두 필요한 구성된 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")
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서