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()을 숨기면 나중에 이를 자유롭게 변경하거나 제거할 수 있습니다. 정보 은닉은 패키지가 외부 사용자에게 약속하는 내용과 내부적으로 작동하는 방식을 명확하게 구분하는 경계를 만듭니다.
챌린지
쉬움정보 은닉을 보여 주는 안전한 지갑 시스템을 만들어 봅시다. 내부 잔액 추적과 거래 내역이 외부 코드에서 완전히 숨겨지는 digital 지갑을 만들게 됩니다. 외부에는 메서드를 통해 동작만 노출됩니다.
코드를 두 파일에 나누어 구성합니다.
wallet.go: 모든 내부 상태를 숨기는Wallet구조체를 Create합니다. 지갑은 current 잔액과 spending limit을 내부적으로 추적해야 하지만, 외부 코드는 이러한 값이 어떻게 저장되거나 표현되는지 절대 알 수 없어야 합니다. 다음 메서드를 통해 동작을 노출합니다.NewWallet(limit float64) *Wallet- 주어진 spending limit과 zero balance로 지갑을 creates하는 constructorDeposit(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])
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: 두 번째 지출 수행 및 결과 출력
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러