Menu
Coddy logo textTech

Go에서의 정보 은닉

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

정보 은닉은 단순히 fields를 내보내지 않도록 만드는 것 이상입니다. 이는 외부 코드가 알아야 할 것만 알도록 타입을 설계하는 것입니다. 그 이상은 알지 못하게 합니다.

목표는 내부 구조를 완전히 숨긴 채 메서드를 통해 동작을 노출하는 것입니다. 다음 접근 방식을 Consider해 보세요:

type Counter struct {
    value    int
    maxLimit int
}

func NewCounter(limit int) *Counter {
    return &Counter{maxLimit: limit}
}

func (c *Counter) Increment() bool {
    if c.value >= c.maxLimit {
        return false
    }
    c.value++
    return true
}

func (c *Counter) Value() int {
    return c.value
}

외부 코드는 Counter가 내부적으로 int를 사용한다는 사실을 알지 못합니다. 그것은 float64일 수도 있고, 슬라이스일 수도 있으며, 완전히 다른 것일 수도 있습니다. 메서드가 동일한 방식으로 작동하는 한, Counter를 사용하는 코드에 영향을 주지 않고 implementation을 변경할 수 있습니다.

이 원칙은 helper functions에도 적용됩니다. internal logic은 Exported되지 않도록 유지하세요:

// Exported - 공개 API의 일부
func (c *Counter) Reset() {
    c.value = 0
}

// unexported - 내부 헬퍼
func (c *Counter) isAtLimit() bool {
    return c.value >= c.maxLimit
}

isAtLimit()을 숨기면 나중에 이를 자유롭게 변경하거나 제거할 수 있습니다. 정보 은닉은 패키지가 외부 사용자에게 약속하는 내용과 내부적으로 작동하는 방식을 명확하게 구분하는 경계를 만듭니다.

challenge icon

챌린지

쉬움

정보 은닉을 보여 주는 안전한 지갑 시스템을 만들어 봅시다. 내부 잔액 추적과 거래 내역이 외부 코드에서 완전히 숨겨지는 digital 지갑을 만들게 됩니다. 외부에는 메서드를 통해 동작만 노출됩니다.

코드를 두 파일에 나누어 구성합니다.

  • wallet.go: 모든 내부 상태를 숨기는 Wallet 구조체를 Create합니다. 지갑은 current 잔액과 spending limit을 내부적으로 추적해야 하지만, 외부 코드는 이러한 값이 어떻게 저장되거나 표현되는지 절대 알 수 없어야 합니다. 다음 메서드를 통해 동작을 노출합니다.
    • NewWallet(limit float64) *Wallet - 주어진 spending limit과 zero balance로 지갑을 creates하는 constructor
    • Deposit(amount float64) bool - 지갑에 금액을 adds하고, 성공하면 true를 반환합니다(amount는 양수여야 함).
    • Spend(amount float64) bool - sufficient balance가 exists하고 amount가 spending limit을 exceed하지 않는 경우 금액을 제거하며, 성공하면 true를 반환합니다.
    • Balance() float64 - current balance를 반환합니다.
    • Status() string - 다음 Format의 상태 메시지를 반환합니다: Balance: $[balance] (Limit: $[limit])
    거래가 유효한지 확인하는 것과 같은 helper logic은 export되지 않은 functions 또는 메서드로 유지합니다. 이는 나중에 변경될 수 있는 internal implementation details입니다.
  • main.go: 입력에서 지갑 configuration과 거래를 읽고, 지갑을 Create한 다음, 작업을 수행하고 각 작업 후 결과를 표시합니다.

다음 inputs이 제공됩니다.

  • Line 1: Spending limit
  • Line 2: Deposit amount
  • Line 3: First spend amount
  • Line 4: Second spend amount

지갑을 Create한 후 initial status를 출력합니다. 그런 다음 각 작업을 수행하고, 성공하면 업데이트된 상태를 출력하고, 작업이 거부되면 Transaction failed를 출력합니다. 모든 dollar amounts은 소수점 이하 두 자리로 Format합니다.

예를 들어 50, 100, 30, 80이 given된 경우 출력은 다음과 같아야 합니다.

Balance: $0.00 (Limit: $50.00)
Balance: $100.00 (Limit: $50.00)
Balance: $70.00 (Limit: $50.00)
Transaction failed

잔액이 충분하더라도 $80이 $50 spending limit을 exceed하므로 마지막 거래는 failed합니다. 지갑은 이러한 결정을 내리는 logic을 노출하지 않고 내부적으로 규칙을 적용합니다. 외부 코드는 단순히 메서드를 호출하고 결과를 받을 뿐, internal implementation details은 전혀 알 수 없습니다.

직접 해보기

package main

import (
	"fmt"
)

func main() {
	// 입력 읽기
	var limit float64
	var depositAmount float64
	var spend1 float64
	var spend2 float64

	fmt.Scanln(&limit)
	fmt.Scanln(&depositAmount)
	fmt.Scanln(&spend1)
	fmt.Scanln(&spend2)

	// TODO: 주어진 지출 한도로 새 지갑 생성

	// TODO: 초기 상태 출력

	// TODO: Perform deposit and print result (status or "Transaction failed")

	// TODO: 첫 번째 지출 수행 및 결과 출력

	// TODO: 두 번째 지출 수행 및 결과 출력
}
quiz icon실력 점검

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

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

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