PHpullh
학습 라이브러리/Go/임베딩과 구성 (Embedding & Composition)

GO · 구조체/인터페이스

임베딩과 구성 (Embedding & Composition)

Go는 상속 대신 구조체 임베딩으로 코드를 재사용합니다. 임베딩된 타입의 메서드가 자동으로 승격(promote)되어 외부 구조체에서 직접 호출할 수 있으며, 인터페이스도 임베딩하여 조합할 수 있습니다.

구조체/인터페이스중급embeddingcompositionstructinterfacepromotion

핵심 설명

Go는 상속 대신 구조체 임베딩으로 코드를 재사용합니다. 임베딩된 타입의 메서드가 자동으로 승격(promote)되어 외부 구조체에서 직접 호출할 수 있으며, 인터페이스도 임베딩하여 조합할 수 있습니다.

Go code

package main

import "fmt"

// 1. 구조체 임베딩 기초
type Logger struct {
	Prefix string
}

func (l Logger) Log(msg string) {
	fmt.Printf("[%s] %s\n", l.Prefix, msg)
}

func (l Logger) Error(msg string) {
	fmt.Printf("[%s] ERROR: %s\n", l.Prefix, msg)
}

type Server struct {
	Logger     // 임베딩: Logger의 메서드가 승격됨
	Host string
	Port int
}

// 2. 메서드 오버라이드 (shadowing)
func (s Server) Log(msg string) {
	// 원래 Logger.Log도 호출 가능
	s.Logger.Log(fmt.Sprintf("%s:%d - %s", s.Host, s.Port, msg))
}

// 3. 인터페이스 임베딩
type Reader interface {
	Read(p []byte) (n int, err error)
}

type Writer interface {
	Write(p []byte) (n int, err error)
}

// Reader + Writer 조합
type ReadWriter interface {
	Reader
	Writer
}

// 4. 다중 임베딩
type Metrics struct {
	RequestCount int
}

func (m *Metrics) IncrementRequests() {
	m.RequestCount++
}

func (m Metrics) Report() string {
	return fmt.Sprintf("요청 수: %d", m.RequestCount)
}

type APIServer struct {
	Server     // Logger 포함
	*Metrics   // 포인터 임베딩도 가능
	Version string
}

func main() {
	// 구조체 임베딩 사용
	srv := Server{
		Logger: Logger{Prefix: "WEB"},
		Host:   "localhost",
		Port:   8080,
	}
	srv.Log("서버 시작")          // Server.Log 호출 (오버라이드됨)
	srv.Error("연결 실패")        // Logger.Error 직접 승격

	// 다중 임베딩
	api := APIServer{
		Server:  srv,
		Metrics: &Metrics{},
		Version: "v2",
	}
	api.Log("API 요청 처리")      // Server.Log → Logger.Log
	api.IncrementRequests()       // Metrics.IncrementRequests
	api.IncrementRequests()
	fmt.Println(api.Report())     // "요청 수: 2"
	fmt.Printf("서버: %s:%d (%s)\n", api.Host, api.Port, api.Version)
}

학습 팁

임베딩은 "has-a" 관계이지 "is-a" 관계가 아닙니다. 내부 타입의 메서드가 승격되지만, 다형성(polymorphism)은 인터페이스로 구현하세요.

주의할 점

두 임베딩된 타입에 같은 이름의 메서드가 있으면 컴파일 에러가 발생합니다. 이 경우 외부 구조체에서 명시적으로 어떤 임베딩의 메서드를 호출할지 지정해야 합니다.

자주 묻는 질문

임베딩과 구성 (Embedding & Composition)란 무엇인가요?

Go는 상속 대신 구조체 임베딩으로 코드를 재사용합니다. 임베딩된 타입의 메서드가 자동으로 승격(promote)되어 외부 구조체에서 직접 호출할 수 있으며, 인터페이스도 임베딩하여 조합할 수 있습니다.

임베딩과 구성 (Embedding & Composition) 학습 시 주의할 점은 무엇인가요?

두 임베딩된 타입에 같은 이름의 메서드가 있으면 컴파일 에러가 발생합니다. 이 경우 외부 구조체에서 명시적으로 어떤 임베딩의 메서드를 호출할지 지정해야 합니다.