메서드 체이닝
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 107개 중 81번째.
메서드 체이닝(Method chaining)은 메서드가 수신 객체를 반환하도록 하여, 단일 문장에서 여러 메서드 호출을 연결할 수 있게 하는 기술입니다. 빌더 패턴(Builder pattern)에서 이미 이 기술을 보셨겠지만, 이는 다양한 상황에서 유용하게 쓰이는 독립적인 개념입니다.
핵심은 각 메서드에서 구조체에 대한 포인터를 반환하는 것입니다:
type Query struct {
table string
columns []string
where string
limit int
}
func (q *Query) Select(cols ...string) *Query {
q.columns = cols
return q
}
func (q *Query) From(table string) *Query {
q.table = table
return q
}
func (q *Query) Where(condition string) *Query {
q.where = condition
return q
}
func (q *Query) Limit(n int) *Query {
q.limit = n
return q
}이제 이 호출들을 유연하게 체이닝할 수 있습니다:
query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)이것은 별개의 문장들과 비교했을 때 거의 자연어처럼 읽힙니다. 메서드 체이닝(Method chaining)은 연산이 다른 값을 반환할 필요 없이 객체를 설정하거나 수정할 때 가장 효과적입니다. 이는 쿼리 빌더, 설정 API 및 테스트 어설션 라이브러리에서 흔히 사용됩니다.
체이닝이 제대로 작동하려면 각 메서드는 포인터 리시버를 사용해야 하며 *StructType을 반환해야 함을 기억하세요.
챌린지
쉬움메서드 체이닝을 사용하여 속성과 콘텐츠가 포함된 HTML 태그를 구성하는 유연한 HTML 요소 빌더를 만들어 봅시다! 이것은 메서드 체이닝의 실용적인 응용 사례입니다. HTML 요소를 빌드할 때 거의 자연어처럼 읽히는 API를 만들게 될 것입니다.
코드는 두 개의 파일로 구성됩니다:
element.go: 체이닝 가능한 메서드를 가진 HTML 요소 빌더를 정의합니다.태그 이름, 속성 맵(문자열 대 문자열), 그리고 내부 콘텐츠를 저장하는
Element구조체를 만듭니다. 각각*Element를 반환하는 다음과 같은 체이닝 가능한 메서드들을 작성하세요:NewElement(tag string)- 주어진 태그 이름과 초기화된(비어 있는) 속성 맵을 가진 새로운 Element를 생성하는 생성자Attr(key, value string)- 요소에 속성을 추가합니다.ID(id string)- "id" 속성을 설정하는 편의 메서드Class(class string)- "class" 속성을 설정하는 편의 메서드Content(text string)- 요소의 내부 콘텐츠를 설정합니다.
HTML 문자열을 반환하는
Render()메서드를 추가하세요. 속성은 키를 기준으로 알파벳 순서로 나타나야 합니다. 형식은 다음과 같습니다:<tag attr1="value1" attr2="value2">content</tag>속성이 없으면
<tag>content</tag>만 렌더링합니다. 콘텐츠가 없으면<tag attr="value"></tag>를 렌더링합니다.main.go: 메서드 체이닝을 사용하여 HTML 요소를 빌드합니다.태그 이름을 읽은 다음, 수행할 작업의 횟수를 읽습니다. 각 작업은 다음 중 하나입니다:
id다음에 오는 ID 값class다음에 오는 클래스 값attr다음에 오는 속성 이름과 값 (두 줄)content다음에 오는 콘텐츠 텍스트
모든 작업을 유연하게 체이닝한 다음, 렌더링된 HTML을 출력하세요.
다음과 같은 입력이 제공됩니다:
- 1행: 태그 이름
- 2행: 작업 횟수
- 다음 행들: 작업 유형 및 값(들)
예를 들어, 다음과 같이 주어지면:
div
3
id
container
class
main-content
content
Hello World출력은 다음과 같아야 합니다:
<div class="main-content" id="container">Hello World</div>그리고 다음과 같이 주어지면:
a
3
attr
href
https://example.com
attr
target
_blank
content
Click here출력은 다음과 같아야 합니다:
<a href="https://example.com" target="_blank">Click here</a>그리고 다음과 같이 주어지면:
input
2
attr
type
text
attr
placeholder
Enter name출력은 다음과 같아야 합니다:
<input placeholder="Enter name" type="text"></input>그리고 다음과 같이 주어지면:
p
1
content
Simple paragraph출력은 다음과 같아야 합니다:
<p>Simple paragraph</p>메서드 체이닝을 통해 요소를 읽기 쉬운 방식으로 단계별로 빌드하는 방법을 확인해 보세요. 각 메서드는 요소를 수정하고 다시 반환하므로, 다음 메서드 호출을 직접 연결할 수 있습니다.
치트 시트
메서드 체이닝(Method chaining)은 메서드가 수신자(일반적으로 *StructType)를 반환하여, 단일 문장에서 여러 메서드 호출을 연결할 수 있도록 하는 기술입니다.
각 메서드는 반드시 포인터 수신자를 사용하고 *StructType을 반환해야 합니다:
type Query struct {
table string
columns []string
where string
limit int
}
func (q *Query) Select(cols ...string) *Query {
q.columns = cols
return q
}
func (q *Query) From(table string) *Query {
q.table = table
return q
}
func (q *Query) Where(condition string) *Query {
q.where = condition
return q
}
func (q *Query) Limit(n int) *Query {
q.limit = n
return q
}메서드 호출을 유연하게 연결합니다:
query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)메서드 체이닝은 다른 값을 반환할 필요 없이 객체를 설정하거나 수정하는 작업에서 가장 효과적입니다. 주로 쿼리 빌더, 설정 API, 그리고 테스트 단언(assertion) 라이브러리에서 흔히 사용됩니다.
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 태그 이름 읽기
scanner.Scan()
tagName := scanner.Text()
// 작업 횟수 읽기
scanner.Scan()
numOps, _ := strconv.Atoi(scanner.Text())
// 요소 생성
element := NewElement(tagName)
// 각 작업 처리
for i := 0; i < numOps; i++ {
scanner.Scan()
operation := scanner.Text()
// TODO: 작업 유형에 따라 적절한 메서드를 체이닝하세요.
// 작업은 "id", "class", "attr", 또는 "content"가 될 수 있습니다:
// - "id": 다음 줄을 ID 값으로 읽음
// - "class": 다음 줄을 클래스 값으로 읽음
// - "attr": 다음 두 줄을 읽음 (속성 이름, 그 다음 값)
// - "content": 다음 줄을 콘텐츠 텍스트로 읽음
// 메서드 체이닝을 사용하여 요소를 유연하게 빌드하세요.
_ = operation // 구현 시 이 라인을 제거하세요
}
// 렌더링된 HTML 출력
fmt.Println(element.Render())
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서