Menu
Coddy logo textTech

암시적 구현

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

Java나 C# 같은 많은 객체 지향 언어에서는 implements와 같은 키워드를 사용하여 어떤 타입이 인터페이스를 구현한다는 것을 명시적으로 선언해야 합니다. Go는 다른 접근 방식을 취합니다. 인터페이스 구현은 암시적입니다.

타입은 인터페이스의 모든 메서드를 구현하기만 하면 해당 인터페이스를 충족합니다. 어디에도 관계를 선언할 필요가 없습니다. 컴파일러가 이를 자동으로 판단합니다.

type Writer interface {
    Write(data string) int
}

type FileWriter struct {
    Filename string
}

// FileWriter는 암시적으로 Writer를 구현합니다
func (f FileWriter) Write(data string) int {
    fmt.Println("Writing to", f.Filename)
    return len(data)
}

FileWriterimplements Writer 선언이 없다는 점에 주목하세요. FileWriter에는 인터페이스 시그니처와 일치하는 Write(data string) int 메서드가 있으므로 Writer 인터페이스를 자동으로 만족합니다.

이 설계는 강력한 결과를 가져옵니다. 이미 타입이 존재한 후에도 인터페이스를 정의할 수 있습니다. 서드파티 라이브러리에 필요한 메서드를 가진 타입이 있다면, 원본 코드를 수정하지 않고도 해당 타입이 이미 만족하는 인터페이스를 만들 수 있습니다.

func Save(w Writer, content string) {
    w.Write(content)
}

func main() {
    fw := FileWriter{Filename: "data.txt"}
    Save(fw, "Hello!")  // FileWriter가 Writer를 만족하기 때문에 작동합니다
}

암시적 구현은 Go 코드를 결합도가 낮고 유연하게 유지합니다. 타입은 인터페이스를 미리 알 필요가 없으므로, 독립적인 부분들로 시스템을 구성하기가 더 쉬워집니다.

challenge icon

챌린지

쉬움

Go에서 타입이 인터페이스를 암시적으로 충족하는 방식을 보여 주는 메시지 전달 시스템을 만들어 보겠습니다. 관계를 명시적으로 선언하지 않고도 동일한 인터페이스를 모두 충족하는 서로 다른 messenger 타입을 만들게 됩니다.

코드는 두 개의 파일로 구성합니다:

  • messengers.go: 단일 method Send(message string) string을 가진 Messenger interface를 Define합니다. 그런 다음 이 interface를 암시적으로 충족하는 두 개의 struct를 만듭니다:
    • EmailMessengerAddress field (string)
    • SMSMessengerPhoneNumber field (string)
    각 struct에는 전달 내용을 설명하는 string을 반환하는 Send method가 있어야 합니다. 어느 struct도 Messenger를 implements한다고 명시적으로 선언해서는 안 됩니다. Go는 method 시그니처를 기반으로 그 관계를 automatically 파악합니다.
  • main.go: 모든 Messenger를 accepts하고 메시지 string을 받은 다음 Send를 calling한 결과를 반환하는 DeliverMessage function을 만듭니다. 입력에서 연락처 정보를 읽고, 두 messenger 타입을 모두 생성한 뒤, function을 사용해 각각을 통해 메시지를 전달합니다.

다음 입력이 제공됩니다:

  • 1번째 줄: Email address
  • 2번째 줄: Phone number
  • 3번째 줄: 보낼 메시지

Send method는 다음 형식의 string을 반환해야 합니다:

  • EmailMessenger: Email to [Address]: [message]
  • SMSMessenger: SMS to [PhoneNumber]: [message]

예를 들어 alice@example.com, 555-1234, Hello!가 주어지면 출력은 다음과 같아야 합니다:

Email to alice@example.com: Hello!
SMS to 555-1234: Hello!

여기서 핵심은 DeliverMessage function이 모든 Messenger를 accepts하며, EmailMessengerSMSMessenger 모두 일치하는 Send method를 갖는 것만으로 해당 interface를 충족한다는 점입니다. 어디에도 implements keyword는 없습니다. Go의 암시적 구현이 모든 것을 처리합니다.

직접 해보기

package main

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

// TODO: 어떤 Messenger든 받는 DeliverMessage 함수를 만드세요
// 그리고 메시지 문자열을 받은 다음, Send를 호출한 결과를 반환합니다

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Read email address
	email, _ := reader.ReadString('\n')
	email = email[:len(email)-1]
	
	// 전화번호 읽기
	phone, _ := reader.ReadString('\n')
	phone = phone[:len(phone)-1]
	
	// 메시지 읽기
	message, _ := reader.ReadString('\n')
	if len(message) > 0 && message[len(message)-1] == '\n' {
		message = message[:len(message)-1]
	}
	
	// TODO: 이메일 주소로 EmailMessenger를 만드세요
	
	// TODO: 전화번호로 SMSMessenger를 만드세요
	
	// TODO: DeliverMessage를 사용해 각 메신저를 통해 메시지를 보내세요
	// 그리고 결과를 출력하세요
}
quiz icon실력 점검

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

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

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