다형성 컬렉션
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 107개 중 44번째.
인터페이스의 가장 강력한 응용 사례 중 하나는 동일한 컬렉션에 서로 다른 타입을 저장하는 것입니다. 인터페이스 타입의 슬라이스는 해당 인터페이스를 만족하는 모든 값을 보유할 수 있으므로, 서로 관련이 있지만 다른 타입들을 함께 그룹화할 수 있습니다.
여러 가지 도형을 관리해야 하는 시나리오를 생각해 보세요. 각 타입별로 별도의 슬라이스를 사용하는 대신, 인터페이스 타입의 단일 슬라이스를 사용할 수 있습니다:
type Shape interface {
Area() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
type Rectangle struct{ Width, Height float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func main() {
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 4, Height: 3},
Circle{Radius: 2},
}
for _, s := range shapes {
fmt.Printf("Area: %.2f\n", s.Area())
}
}
shapes 슬라이스는 원과 사각형을 모두 보유합니다. 반복할 때, 각 요소는 실제 타입에 따라 Area()에 응답합니다. 이것은 컬렉션에 적용된 다형성입니다. 동일한 루프가 모든 도형 타입을 균일하게 처리합니다.
다형성 컬렉션은 다양한 항목을 처리하는 시스템을 구축할 때 필수적입니다. 예를 들어 이메일과 SMS 메시지를 보내는 알림 시스템, 서로 다른 적 유형을 업데이트하는 게임, 또는 여러 파일 형식을 처리하는 문서 처리기 등이 있습니다. 컬렉션은 구체적인 유형에는 신경 쓰지 않으며, 각 요소가 필요한 동작을 제공한다는 점만 중요하게 여깁니다.
챌린지
쉬움통합된 인터페이스를 통해 다양한 유형의 작업을 처리하는 작업 관리 시스템을 구축해 보겠습니다. 다양한 작업 유형을 생성하고 이를 다형성 컬렉션(polymorphic collection)에서 함께 처리하게 됩니다.
코드는 다음 세 개의 파일로 구성됩니다:
task.go:Summary() string메서드를 요구하는Task인터페이스를 정의합니다. 이 인터페이스는 모든 작업 유형이 충족해야 하는 공통 계약이 됩니다.types.go:Task인터페이스를 각각 구현하는 세 가지 작업 유형을 생성합니다:BugFix:ID(string) 및Severity(string) 필드를 가짐 —Summary()는Bug #[ID] ([Severity])를 반환합니다.Feature:Name(string) 및Points(int) 필드를 가짐 —Summary()는Feature: [Name] - [Points] pts를 반환합니다.Documentation:Topic(string) 필드를 가짐 —Summary()는Docs: [Topic]을 반환합니다.
main.go:Task슬라이스를 인자로 받아 각 작업의 요약을 개별 줄에 출력하는PrintBacklog함수를 작성합니다. 입력에서 작업 세부 정보를 읽어 각 작업 유형을 하나씩 생성하고, 이를 하나의[]Task슬라이스에 모은 다음PrintBacklog에 전달합니다.
다음과 같은 입력이 제공됩니다:
- 1행: 버그 ID
- 2행: 버그 심각도(severity)
- 3행: 기능(feature) 이름
- 4행: 기능 포인트(정수)
- 5행: 문서화(documentation) 주제
예를 들어, 1042, critical, Dark Mode, 8, API Reference가 주어지면 출력은 다음과 같아야 합니다:
Bug #1042 (critical)
Feature: Dark Mode - 8 pts
Docs: API Reference여기서 핵심은 PrintBacklog가 버그, 기능 또는 문서에 대해 별도의 로직을 가질 필요가 없다는 점입니다. 단순히 슬라이스를 순회하며 각 요소의 Summary()를 호출할 뿐입니다. 각 작업 유형은 자신만의 고유한 형식으로 응답하며, 이는 다형성 컬렉션이 어떻게 다양한 유형을 균일하게 처리할 수 있게 해주는지 보여줍니다.
치트 시트
인터페이스 타입의 슬라이스는 해당 인터페이스를 충족하는 모든 값을 보유할 수 있어 다형성 컬렉션을 가능하게 합니다:
type Shape interface {
Area() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
type Rectangle struct{ Width, Height float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func main() {
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 4, Height: 3},
Circle{Radius: 2},
}
for _, s := range shapes {
fmt.Printf("Area: %.2f\n", s.Area())
}
}
shapes 슬라이스는 Shape 인터페이스를 모두 구현하는 서로 다른 타입(Circle 및 Rectangle)을 보유합니다. 반복문을 실행할 때, 각 요소는 실제 타입에 따라 Area()에 응답하며, 이것이 컬렉션에 적용된 다형성입니다.
이 패턴은 다양한 항목을 균일하게 처리하는 데 유용합니다. 예를 들어 서로 다른 메시지 타입을 처리하는 알림 시스템, 다양한 적 타입을 업데이트하는 게임, 또는 여러 파일 형식을 처리하는 문서 프로세서 등이 있습니다.
직접 해보기
package main
import (
"fmt"
)
// TODO: Task 슬라이스를 매개변수로 받아 각 작업의 요약(summary)을
// 개별 줄에 출력하는 PrintBacklog 함수를 생성하세요.
func main() {
// 입력 읽기
var bugID string
var bugSeverity string
var featureName string
var featurePoints int
var docTopic string
fmt.Scanln(&bugID)
fmt.Scanln(&bugSeverity)
fmt.Scanln(&featureName)
fmt.Scanln(&featurePoints)
fmt.Scanln(&docTopic)
// TODO: 각 작업 유형(BugFix, Feature, Documentation)을 하나씩 생성하세요.
// TODO: 모든 작업을 하나의 []Task 슬라이스에 수집하세요.
// TODO: 작업 슬라이스를 사용하여 PrintBacklog를 호출하세요.
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서