Go에서의 정보 은닉
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 107개 중 50번째.
정보 은닉(Information hiding)은 단순히 필드를 내보내지 않는(unexported) 것 이상의 의미를 갖습니다. 이는 외부 코드가 꼭 알아야 할 정보만 알고 그 이상은 알지 못하도록 타입을 설계하는 것에 관한 것입니다.
목표는 내부 구조를 완전히 숨긴 채로 메서드를 통해 동작을 노출하는 것입니다. 다음 접근 방식을 고려해 보세요:
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를 사용하는 코드에 영향을 주지 않고 구현을 변경할 수 있습니다.
이 원칙은 헬퍼 함수에도 적용됩니다. 내부 로직은 내보내지 않은(unexported) 상태로 유지하세요:
// 내보내기됨 - 공개 API의 일부
func (c *Counter) Reset() {
c.value = 0
}
// 내보내기되지 않음 - 내부 헬퍼
func (c *Counter) isAtLimit() bool {
return c.value >= c.maxLimit
}
isAtLimit()을 숨김으로써, 나중에 이를 자유롭게 변경하거나 제거할 수 있습니다. 정보 은닉은 패키지가 외부 사용자에게 약속하는 것과 내부적으로 작동하는 방식 사이에 명확한 경계를 만듭니다.
챌린지
쉬움정보 은닉을 보여주는 보안 지갑 시스템을 구축해 봅시다. 내부 잔액 추적 및 거래 내역이 외부 코드로부터 완전히 숨겨지고, 오직 메서드를 통해서만 동작이 노출되는 디지털 지갑을 만들 것입니다.
코드는 두 개의 파일로 구성합니다:
wallet.go: 모든 내부 상태를 숨기는Wallet구조체를 생성합니다. 지갑은 내부적으로 현재 잔액과 지출 한도를 추적해야 하지만, 외부 코드에서는 이것들이 어떻게 저장되거나 표현되는지 알 수 없어야 합니다. 다음 메서드들을 통해 동작을 노출하세요:NewWallet(limit float64) *Wallet- 주어진 지출 한도와 잔액 0으로 지갑을 생성하는 생성자Deposit(amount float64) bool- 지갑에 돈을 추가하며, 성공하면true를 반환합니다 (금액은 양수여야 함)Spend(amount float64) bool- 잔액이 충분하고 금액이 지출 한도를 초과하지 않는 경우 돈을 차감하며, 성공하면true를 반환합니다Balance() float64- 현재 잔액을 반환합니다Status() string-Balance: $[balance] (Limit: $[limit])형식의 상태 메시지를 반환합니다
main.go: 입력으로부터 지갑 설정 및 트랜잭션을 읽고, 지갑을 생성하고, 작업을 수행하며, 각 작업 후 결과를 표시합니다.
다음 입력이 제공됩니다:
- 1행: 지출 한도
- 2행: 입금 금액
- 3행: 첫 번째 지출 금액
- 4행: 두 번째 지출 금액
지갑을 생성한 후 초기 상태를 출력하세요. 그런 다음 각 작업을 수행하고 업데이트된 상태(성공 시) 또는 Transaction failed(작업이 거부된 경우)를 출력하세요. 모든 달러 금액은 소수점 둘째 자리까지 표시합니다.
예를 들어, 50, 100, 30, 80이 주어지면 출력은 다음과 같아야 합니다:
Balance: $0.00 (Limit: $50.00)
Balance: $100.00 (Limit: $50.00)
Balance: $70.00 (Limit: $50.00)
Transaction failed마지막 트랜잭션은 잔액이 충분하더라도 $80가 지출 한도 $50를 초과하기 때문에 실패합니다. 지갑은 이러한 결정을 내리는 방식을 노출하지 않고 내부적으로 규칙을 적용합니다. 외부 코드는 단순히 메서드를 호출하고 결과를 받을 뿐이며, 내부 구현 세부 사항은 전혀 알지 못합니다.
치트 시트
정보 은닉이란 외부 코드에서 꼭 알아야 할 내용만 알 수 있도록 타입을 설계하는 것을 의미합니다. 내부 구조는 완전히 숨긴 채 메서드를 통해 동작을 노출하세요.
구현이 숨겨진 타입의 예시:
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
}
외부 코드는 내부 표현 방식(int, float64 또는 다른 무엇이든 될 수 있음)을 알지 못합니다. 이를 사용하는 코드에 영향을 주지 않고 구현을 변경할 수 있습니다.
헬퍼 함수는 비공개(unexported)로 유지하세요:
// 공개(Exported) - 퍼블릭 API의 일부
func (c *Counter) Reset() {
c.value = 0
}
// 비공개(unexported) - 내부 헬퍼
func (c *Counter) isAtLimit() bool {
return c.value >= c.maxLimit
}
정보 은닉은 패키지가 외부로 약속하는 것과 내부적으로 작동하는 방식 사이에 명확한 경계를 만듭니다.
직접 해보기
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: 입금을 수행하고 결과 출력 (상태 또는 "Transaction failed")
// TODO: 첫 번째 지출을 수행하고 결과 출력
// TODO: 두 번째 지출을 수행하고 결과 출력
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서