Menu
Coddy logo textTech

여러 구조체 임베딩하기

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

Go에서는 하나의 구조체 안에 여러 구조체를 임베드하여 서로 다른 소스의 동작을 결합할 수 있습니다. 이는 다른 언어의 다중 상속과 유사하지만, Go의 컴포지션 접근 방식을 사용합니다.

type Logger struct{}

func (l Logger) Log(msg string) string {
    return "LOG: " + msg
}

type Notifier struct{}

func (n Notifier) Notify(msg string) string {
    return "NOTIFY: " + msg
}

type Service struct {
    Name string
    Logger
    Notifier
}

이제 Service 구조체는 두 임베디드 타입의 메서드에 모두 액세스할 수 있습니다:

func main() {
    s := Service{Name: "OrderService"}
    fmt.Println(s.Log("started"))      // LOG: 시작됨
    fmt.Println(s.Notify("new order")) // NOTIFY: 새 주문
}

여러 구조체를 임베딩할 때, 두 임베딩된 타입에 같은 이름의 메서드가 있으면 naming conflict가 발생할 수 있습니다. Go는 이 모호성을 자동으로 해결하지 않습니다.

type A struct{}
func (A) Greet() string { return "Hello from A" }

type B struct{}
func (B) Greet() string { return "Hello from B" }

type Combined struct {
    A
    B
}

func main() {
    c := Combined{}
    // c.Greet() - 컴파일 오류: 모호한 선택자
    fmt.Println(c.A.Greet())  // Hello from A
    fmt.Println(c.B.Greet())  // Hello from B
}

충돌이 발생하면, call하려는 embedded type의 method를 type name을 한정자로 사용하여 explicitly 지정해야 합니다.

challenge icon

챌린지

쉬움

struct 임베딩을 통해 여러 기능을 결합하는 스마트 홈 device 시스템을 만들어 봅시다. 별도의 controller 타입을 임베딩하여 조명을 제어하고 음악을 재생할 수 있는 device를 만듭니다.

코드를 세 개의 파일로 구성합니다:

  • controllers.go: 서로 다른 기능을 제공하는 두 개의 독립적인 controller struct를 Create합니다:
    • LightController에는 Brightness field (int)와 SetLight(level int) string method가 있으며, 이 method는 Light set to [level]%을 반환합니다.
    • AudioController에는 Volume field (int)와 SetVolume(level int) string method가 있으며, 이 method는 Volume set to [level]%을 반환합니다.
    두 controller 모두 Status() string method도 가져야 합니다. 이로 인해 처리해야 할 naming conflict이 발생합니다. LightController.Status()Brightness: [Brightness]%를 반환하고, AudioController.Status()Volume: [Volume]%을 반환해야 합니다.
  • device.go: LightControllerAudioController를 모두 임베딩하고 Name field를 가진 SmartDevice struct를 Create합니다. device 이름과 두 controller의 status를 함께 반환하는 FullStatus() string method를 추가하고, 각 임베딩된 타입의 Status() method를 명시적으로 호출하여 ambiguous한 상황을 resolve합니다.
  • main.go: input에서 device 구성을 Read하고, SmartDevice를 Create한 다음, promoted method를 사용하여 조명과 음량 level을 설정하고 전체 status를 표시합니다.

다음 input이 제공됩니다:

  • 1번째 줄: device 이름
  • 2번째 줄: initial brightness level (정수)
  • 3번째 줄: initial volume level (정수)
  • 4번째 줄: 설정할 new brightness level (정수)
  • 5번째 줄: 설정할 new volume level (정수)

FullStatus() method는 다음을 반환해야 합니다:

[Name] - [LightController.Status()], [AudioController.Status()]

SetLightSetVolume을 호출한 결과를 출력하세요. 이 method들은 임베딩된 타입에서 promoted됩니다. 그런 다음 전체 status를 출력하세요.

예를 들어 Living Room Hub, 50, 30, 75, 60이 주어졌다면 출력은 다음과 같아야 합니다:

Light set to 75%
Volume set to 60%
Living Room Hub - Brightness: 75%, Volume: 60%

SetLightSetVolume은 method promotion을 통해 SmartDevice에서 직접 접근할 수 있지만, 두 임베딩된 타입 모두 해당 method를 가지고 있으므로 Status()에는 명시적인 qualification이 필요하다는 점에 유의하세요.

직접 해보기

package main

import (
	"fmt"
)

func main() {
	// 입력 읽기
	var name string
	fmt.Scanln(&name)

	var initialBrightness int
	fmt.Scanln(&initialBrightness)

	var initialVolume int
	fmt.Scanln(&initialVolume)

	var newBrightness int
	fmt.Scanln(&newBrightness)

	var newVolume int
	fmt.Scanln(&newVolume)

	// TODO: 주어진 이름과 초기값으로 SmartDevice 생성

	// TODO: 승격된 SetLight 메서드를 사용하고 결과 출력

	// TODO: 승격된 SetVolume 메서드를 사용하고 결과 출력

	// TODO: FullStatus() 메서드를 사용하여 전체 상태 출력
}
quiz icon실력 점검

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

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

직접 연습해 보세요: 온라인 Go 컴파일러