Menu
Coddy logo textTech

계약으로서의 인터페이스

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

인터페이스를 계약으로 생각하면 더 나은 Go 프로그램을 설계하는 데 도움이 됩니다. 함수가 인터페이스 타입을 받는다는 것은 다음과 같이 말하는 것입니다. "이 계약을 충족하기만 한다면 어떤 구체 타입을 전달하든 상관하지 않습니다."

이 계약 기반 사고방식을 사용하면 특정 타입이 아니라 동작에 초점을 맞춘 함수를 작성할 수 있습니다. 다양한 소스의 데이터를 처리해야 하는 함수를 생각해 보세요.

type DataSource interface {
    FetchData() string
}

func ProcessData(src DataSource) {
    data := src.FetchData()
    fmt.Println("Processing:", data)
}

ProcessData function은 데이터베이스 연결, API 클라이언트 또는 파일 리더 중 무엇을 받는지 알지도 신경 쓰지도 않습니다. 입력이 FetchData()를 수행할 수 있기만 하면 됩니다. 이 contract를 준수하는 모든 타입이 작동합니다.

type Database struct{ ConnectionString string }
func (d Database) FetchData() string { return "data from DB" }

type APIClient struct{ Endpoint string }
func (a APIClient) FetchData() string { return "data from API" }

func main() {
    db := Database{ConnectionString: "localhost"}
    api := APIClient{Endpoint: "https://api.example.com"}
    
    ProcessData(db)   // 작동합니다!
    ProcessData(api)  // 또한 작동합니다!
}

이 contract 접근 방식은 코드를 더 쉽게 테스트할 수 있게 해 줍니다. 테스트하는 동안 실제 데이터베이스나 네트워크 연결 없이도 interface를 충족하는 mock 타입을 만들 수 있습니다. 테스트 중인 function은 contract가 충족되기 때문에 둘의 차이를 알지 못합니다.

challenge icon

챌린지

쉬움

interfacecontract로 작동하는 방식을 보여 주는 notification 시스템을 만들어 보겠습니다. notification을 보내는 것이 무엇을 의미하는지 정의하는 Notifier interface를 만든 다음, 이 contract를 모두 준수하는 여러 notification 채널을 구현합니다.

코드를 두 파일로 구성합니다.

  • notifiers.go: 하나의 method Notify(message string) string을 포함하는 Notifier interface를 Define합니다. 그런 다음 이 contract를 충족하는 세 가지 서로 다른 구조체를 만듭니다.
    • ConsoleNotifier에는 Prefix field가 있습니다.
    • FileNotifier에는 Filename field가 있습니다.
    • WebhookNotifier에는 URL field가 있습니다.
    각 구조체는 Notify method를 Implement하여 notification이 어떻게 전송되는지를 설명하는 문자열을 반환해야 합니다.
  • main.go: Notifier 값의 슬라이스와 메시지 문자열을 인수로 받는 BroadcastAlert이라는 function을 만듭니다. 이 function은 각 notifier에서 Notify를 호출하고 결과를 출력해야 합니다. 입력에서 구성을 읽고, 세 가지 notifier 유형을 모두 만든 다음, 이들 모두를 통해 alert를 브로드캐스트합니다.

다음 입력이 제공됩니다.

  • 1번째 줄: Console 접두사
  • 2번째 줄: Filename
  • 3번째 줄: Webhook URL
  • 4번째 줄: Alert message

여러분의 Notify method는 다음 형식의 문자열을 반환해야 합니다.

  • ConsoleNotifier: [Prefix] [message]
  • FileNotifier: Writing to [Filename]: [message]
  • WebhookNotifier: POST [URL]: [message]

예를 들어 ALERT:, log.txt, https://hooks.example.com, Server down!이 주어지면 출력은 다음과 같아야 합니다.

ALERT: Server down!
Writing to log.txt: Server down!
POST https://hooks.example.com: Server down!

이 설계의 장점은 BroadcastAlert function이 특정 notifier 유형을 알 필요도, 신경 쓸 필요도 없다는 것입니다. 각 notifier가 Notifier contract를 충족하기만 하면 됩니다. 나중에 브로드캐스트 function을 전혀 변경하지 않고 SlackNotifier 또는 EmailNotifier를 추가할 수도 있습니다.

직접 해보기

package main

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

// BroadcastAlert는 모든 notifier를 통해 메시지를 전송합니다
// TODO: 이 함수를 다음과 같이 구현하세요:
// - Notifier 값의 슬라이스와 메시지 문자열을 받습니다
// - 각 notifier에서 Notify를 호출하고 결과를 출력합니다
func BroadcastAlert(notifiers []Notifier, message string) {
	// TODO: notifier를 순회하며 각 알림 결과를 출력합니다
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// 콘솔 prefix 읽기
	scanner.Scan()
	prefix := scanner.Text()
	
	// 파일 이름 읽기
	scanner.Scan()
	filename := scanner.Text()
	
	// 웹훅 URL 읽기
	scanner.Scan()
	url := scanner.Text()
	
	// 알림 메시지 읽기
	scanner.Scan()
	message := scanner.Text()
	
	// TODO: 세 가지 notifier 유형의 인스턴스를 모두 생성합니다
	// - prefix가 있는 ConsoleNotifier
	// - filename이 있는 FileNotifier
	// - URL을 가진 WebhookNotifier
	
	// TODO: 세 개의 notifier를 모두 포함하는 Notifier 슬라이스 생성
	
	// TODO: notifiers와 message로 BroadcastAlert 호출
	
	_ = prefix
	_ = filename
	_ = url
	_ = message
	fmt.Println("TODO: Implement the solution")
}
quiz icon실력 점검

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

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

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