Menu
Coddy logo textTech

임베딩 vs 집약

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

embedding이 필드와 메서드를 외부 구조체로 승격한다는 것을 배웠습니다. 하지만 Go는 이름이 지정된 필드로 다른 구조체를 포함하는 aggregation도 지원합니다. 각 접근 방식을 언제 사용할지 이해하는 것은 좋은 설계의 핵심입니다.

embedding을 사용하면 field 이름을 생략하고, 내부 타입의 멤버에 직접 access할 수 있습니다:

type Writer struct{}
func (w Writer) Write() string { return "writing" }

type Document struct {
    Writer  // 임베딩 - 필드 이름 없음
}

d := Document{}
d.Write()  // 직접 접근

aggregation을 사용하면 fieldexplicit 이름을 지정하므로, 내부 타입에 access할 때 해당 이름을 사용해야 합니다:

type Document struct {
    writer Writer  // 집약 - 이름이 있는 필드
}

d := Document{writer: Writer{}}
d.writer.Write()  // 필드 이름을 사용해야 함

표현하려는 관계가 핵심적인 차이입니다. Embedding은 바깥쪽 타입이 안쪽 타입의 정체성을 갖게 되는 "is-a" 관계를 의미합니다. 집계는 바깥쪽 타입이 안쪽 타입을 단순히 포함하는 "has-a" 관계를 의미합니다.

내부 타입이 구현한 인터페이스를 외부 타입이 만족하도록 하려는 경우, 또는 direct 메서드 접근으로 API를 더 깔끔하게 만들 수 있는 경우에는 embedding을 사용하세요. 내부 타입이 노출해서는 안 되는 implementation 세부 사항인 경우, 또는 내부 타입에 access하는 방식을 명시적으로 제어하려는 경우에는 aggregation을 사용하세요.

challenge icon

챌린지

쉬움

embedding과 aggregation 중 언제 사용해야 하는지 보여 주는 보고서 생성 시스템을 만들어 보겠습니다. 일부 구성 요소는 직접 access할 수 있어야 하고(embedding), 다른 구성 요소는 internal implementation detail로 유지되어야 하는(aggregation) 시스템을 만들게 됩니다.

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

  • formatter.go: Style field(string)과 스타일을 사용해 텍스트를 감싸 반환하는 Format(text string) string method를 포함하는 Formatter struct를 Create합니다. 예: [Style] text [/Style]. 이는 직접 노출해서는 안 되는 internal helper입니다.
  • report.go: 보고서 생성을 서로 다르게 처리하는 두 개의 struct를 Create합니다:
    • AuthorDate fields를 포함하는 Metadata struct. 이는 직접 access할 수 있어야 하는 public information을 나타냅니다.
    • Title field가 있고, Metadataembeds하여 author와 date에 직접 access할 수 있도록 하며, Formatter에는 aggregation을 사용하는 Report struct입니다. Formatter는 named field formatter를 사용하는 internal implementation detail입니다.
    ReportGenerate() string method를 Add합니다. 이 method는 internal formatter를 사용해 title을 formatted하고 metadata를 포함해야 합니다.
  • main.go: input에서 보고서 세부 정보를 읽고, embedded metadata와 aggregated formatter를 모두 포함하는 Report를 Create합니다. embedding을 통해 report에서 author에 직접 access한 다음, hidden formatter를 내부적으로 사용하는 formatted report를 Generate하여 차이를 보여 줍니다.

다음 input이 제공됩니다:

  • 1번째 줄: Report title
  • 2번째 줄: Author name
  • 3번째 줄: Date
  • 4번째 줄: Formatter style

Format method는 다음을 반환해야 합니다:

[Style] text [/Style]

Generate method는 다음을 반환해야 합니다:

[formatted title]
Author: [Author], Date: [Date]

main file에서 세 줄을 print합니다:

  1. Report에서 직접 access한 author(embedding이 field를 promote한다는 것을 demonstrates)
  2. embedded type name을 통해 access한 date(report.Metadata.Date)
  3. Generate()를 calling한 결과

예를 들어 Quarterly Results, Jane Doe, 2024-01-15, BOLD가 주어지면 output은 다음과 같아야 합니다:

Jane Doe
2024-01-15
[BOLD] Quarterly Results [/BOLD]
Author: Jane Doe, Date: 2024-01-15

AuthorDate는 embedding을 통해 Report에서 직접 access할 수 있지만 formatter는 hidden 상태로 유지된다는 점에 주목하세요. formatter가 named field로 aggregated되어 있으므로 report.Format()을 직접 calling할 수 없습니다. 이는 실제로 "is-a"와 "has-a" 관계를 demonstrates합니다.

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	scanner.Scan()
	title := scanner.Text()
	
	scanner.Scan()
	author := scanner.Text()
	
	scanner.Scan()
	date := scanner.Text()
	
	scanner.Scan()
	style := scanner.Text()
	
	// TODO: author와 date를 가진 Metadata 구조체를 생성하세요
	
	// TODO: 주어진 style로 Formatter를 생성하세요
	
	// TODO: Metadata를 임베드하고 Formatter를 집약하는 Report를 생성하세요
	
	// TODO: Report에서 직접 접근한 author를 출력하세요 (임베딩이 필드를 승격시킴)
	
	// TODO: 임베드된 타입 이름을 통해 접근한 date를 출력하세요 (report.Metadata.Date)
	
	// TODO: Generate() 호출 결과를 출력하세요
	
	// 사용하지 않는 변수 경고를 억제합니다 (변수를 사용할 때 이들을 제거하세요)
	_ = title
	_ = author
	_ = date
	_ = style
}
quiz icon실력 점검

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

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

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