임베딩된 메서드 섀도잉
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 107개 중 39번째.
때로는 외부 구조체가 임베디드된 타입이 이미 가지고 있는 메서드에 대해 자체적인 구현을 제공해야 할 때가 있습니다. 이것을 섀도잉(shadowing)이라고 하며, 이를 통해 승격된 메서드를 사용자 정의 동작으로 오버라이드할 수 있습니다.
임베디드 메서드와 동일한 이름의 메서드를 외부 구조체에 정의하면, 외부 메서드가 우선순위를 갖습니다:
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
이제 Dog에서 Speak()를 호출하면, 외부 메서드가 사용됩니다:
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - Dog의 메서드
fmt.Println(d.Animal.Speak()) // Some sound - Animal의 메서드
}
임베디드된 메서드는 사라지지 않습니다. 임베디드된 타입 이름을 통해 명시적으로 접근할 수 있습니다. 이 패턴은 원래의 구현을 유지하면서 동작을 커스터마이징하고 싶을 때 유용하며, 아마도 오버라이딩하는 메서드 내부에서 이를 호출하기 위해 사용될 수 있습니다:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
섀도잉은 명시적 한정을 통해 원본에 대한 접근을 유지하면서 어떤 동작을 노출할지 제어할 수 있게 해줍니다.
챌린지
쉬움다양한 알림 채널이 메시지를 형식화하고 전달하는 방식을 맞춤 설정할 수 있는 알림 시스템을 구축해 보겠습니다. 메서드 섀도잉(method shadowing)을 사용하여 특정 채널이 기본 동작을 재정의하도록 하면서도, 필요한 경우 원래의 구현에 여전히 접근할 수 있도록 할 것입니다.
코드는 세 개의 파일로 구성됩니다:
base.go:Title과Priority필드(둘 다 문자열)를 가진BaseNotification구조체를 생성합니다. 이 구조체에 표준 형식인[Priority] Title을 반환하는Format() string메서드를 추가합니다.channels.go:BaseNotification을 임베딩하고Format메서드를 각자의 구현으로 섀도잉하는 두 가지 알림 채널 타입을 생성합니다:Recipient필드를 가진EmailNotification—이 타입의Format()은Email to [Recipient]: [Priority] Title을 반환해야 합니다.Channel필드를 가진SlackNotification—이 타입의Format()은 임베딩된BaseNotification.Format()메서드를 호출하고 그 결과 앞에#[Channel]:를 붙여야 합니다.
main.go: 입력으로부터 알림 세부 정보를 읽고, 두 타입의 알림을 모두 생성한 후 다음을 출력하여 섀도잉을 시연합니다:EmailNotification의 형식화된 출력 (섀도잉된 메서드 사용)EmailNotification의 기본 형식 (임베딩된 메서드를 명시적으로 호출)SlackNotification의 형식화된 출력 (내부적으로 기본 메서드를 사용)
다음 입력이 제공됩니다:
- 1행: 알림 제목 (Notification title)
- 2행: 우선순위 레벨 (Priority level)
- 3행: 이메일 수신자 (Email recipient)
- 4행: Slack 채널 이름 (Slack channel name)
예를 들어, Server Alert, HIGH, admin@company.com, ops-alerts가 주어지면 출력은 다음과 같아야 합니다:
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server AlertEmailNotification이 기본 포맷팅을 완전히 대체하는 방식과, SlackNotification이 원래 메서드를 호출하고 채널 컨텍스트를 추가하여 이를 강화하는 방식의 차이를 확인해 보세요. 두 접근 방식 모두 메서드 섀도잉을 효과적으로 사용하는 서로 다른 방법을 보여줍니다.
치트 시트
외부 구조체에 임베디드 타입의 메서드와 동일한 이름의 메서드를 정의하면, 외부 메서드가 임베디드 메서드를 가립니다(재정의합니다):
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
외부 구조체에서 메서드를 호출할 때, 외부 메서드가 우선순위를 갖습니다:
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - Dog의 메서드
fmt.Println(d.Animal.Speak()) // Some sound - Animal의 메서드
임베디드 메서드는 임베디드 타입 이름을 사용한 명시적 한정을 통해 여전히 접근 가능합니다. 재정의하는 메서드 내에서 원래의 구현을 호출할 수 있습니다:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 알림 제목 읽기
scanner.Scan()
title := scanner.Text()
// 우선순위 레벨 읽기
scanner.Scan()
priority := scanner.Text()
// 이메일 수신자 읽기
scanner.Scan()
recipient := scanner.Text()
// 슬랙 채널 이름 읽기
scanner.Scan()
channel := scanner.Text()
// TODO: 기본 알림, 제목, 우선순위 및 수신자를 사용하여 EmailNotification 생성
// TODO: 기본 알림, 제목, 우선순위 및 채널을 사용하여 SlackNotification 생성
// TODO: EmailNotification의 형식화된 출력 인쇄 (섀도잉된 메서드 사용)
// TODO: EmailNotification의 기본 형식 인쇄 (임베디드 메서드를 명시적으로 호출)
// TODO: SlackNotification의 형식화된 출력 인쇄
fmt.Println() // 자리 표시자 - 구현 시 제거
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서