Menu
Coddy logo textTech

패키지 수준의 캡슐화

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

이전 레슨에서는 필드 수준의 가시성을 다뤘지만, Go의 캡슐화는 실제로 패키지 수준에서 작동합니다. 같은 패키지에 있는 모든 항목은 어느 파일에 있든 관계없이 내보내지 않은 필드와 함수에 액세스할 수 있습니다.

여러 파일로 구성된 패키지를 생각해 보세요:

// account/account.go
package account

type Account struct {
    balance int  // 비공개
}

func (a *Account) Deposit(amount int) {
    a.balance += amount
}
// account/helper.go
package account

func ResetAccount(a *Account) {
    a.balance = 0  // 작동함 - 같은 패키지
}

두 파일 모두 account 패키지에 속하므로, helper.go는 내보내지 않은 balance field에 직접 액세스할 수 있습니다. 이는 의도된 동작입니다. 이를 통해 내부 액세스를 유지하면서 패키지 로직을 여러 파일로 나눌 수 있습니다.

하지만 패키지 외부의 코드는 내보내지 않은 멤버에 액세스할 수 없습니다:

// main.go
package main

import "account"

func main() {
    acc := &account.Account{}
    acc.Deposit(100)        // 작동함 - 내보낸 메서드
    // acc.balance = 50     // 오류 - 내보내지 않은 필드
    // account.ResetAccount // ResetAccount가 내보내졌다면 작동함
}

이 패키지 수준의 경계는 Go의 주요 캡슐화 메커니즘입니다. 내부 코드가 자유롭게 협력하는 응집력 있는 단위로 패키지를 설계하는 한편, 외부 코드는 Exported API를 통해서만 상호 작용합니다. 각 패키지를 명확한 공개 인터페이스를 갖춘 독립적인 모듈이라고 생각하세요.

challenge icon

챌린지

쉬움

내보내지 않은 필드에 직접 액세스하여 동일한 패키지 내 여러 파일이 협력하는 방식을 보여 주면서, 외부 코드에서는 해당 데이터를 숨기는 재고 관리 시스템을 만들어 보겠습니다.

main 패키지에서 함께 작동하는 세 개의 파일을 만듭니다.

  • product.go: 내보낸 Name 필드와 내보내지 않은 quantity 필드(int)를 포함하는 Product 구조체를 정의합니다. [Name]: [quantity] in stock 형식을 반환하는 내보낸 메서드 Info() string을 추가합니다.
  • inventory.go: 내보내지 않은 quantity 필드에 직접 액세스하여 제품과 함께 작동하는 helper 함수를 만듭니다(동일한 패키지에 있으므로 가능합니다). 다음을 Implement합니다.
    • Restock(p *Product, amount int) - 제품의 수량에 amount를 더합니다.
    • Sell(p *Product, amount int) bool - 충분한 재고가 있으면 수량에서 amount를 빼고, 성공하면 true를 반환하며 재고가 enough하지 않으면 false를 반환합니다.
    • NewProduct(name string, initialQty int) *Product - given 이름과 initial 수량으로 제품을 creates하는 constructor입니다.
  • main.go: 입력에서 제품 정보를 읽고, constructor를 사용하여 제품을 만들고, 재고 작업을 수행한 다음 결과를 표시합니다. 각 작업 후 제품 info를 출력하여 업데이트된 상태를 보여 줍니다.

다음 입력이 제공됩니다.

  • 1번째 줄: Product 이름
  • 2번째 줄: Initial 수량(정수)
  • 3번째 줄: Restock amount(정수)
  • 4번째 줄: Sell amount(정수)

제품을 만든 후 initial info를 출력합니다. 그런 다음 restock하고 info를 다시 출력합니다. 마지막으로 sell을 시도하고, 성공하면 업데이트된 info를 출력하고, quantity가 enough하지 않으면 Sale failed: insufficient stock을 출력합니다.

예를 들어 Laptop, 10, 5, 8이 주어지면 출력은 다음과 같아야 합니다.

Laptop: 10 in stock
Laptop: 15 in stock
Laptop: 7 in stock

또한 Phone, 3, 2, 10이 주어지면 출력은 다음과 같아야 합니다.

Phone: 3 in stock
Phone: 5 in stock
Sale failed: insufficient stock

여기서 핵심은 inventory.goproduct.go와 동일한 패키지에 있기 때문에 내보내지 않은 quantity 필드를 직접 읽고 수정할 수 있다는 점입니다. 이것이 바로 패키지 수준 캡슐화입니다. 내부 협력은 자유롭게 이루어지는 동시에 데이터는 외부 패키지로부터 보호됩니다.

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 제품 이름 읽기
	name, _ := reader.ReadString('\n')
	name = strings.TrimSpace(name)

	// 초기 수량 읽기
	initialQtyStr, _ := reader.ReadString('\n')
	initialQty, _ := strconv.Atoi(strings.TrimSpace(initialQtyStr))

	// 재입고 수량 읽기
	restockStr, _ := reader.ReadString('\n')
	restockAmount, _ := strconv.Atoi(strings.TrimSpace(restockStr))

	// 판매 수량 읽기
	sellStr, _ := reader.ReadString('\n')
	sellAmount, _ := strconv.Atoi(strings.TrimSpace(sellStr))

	// TODO: NewProduct 생성자를 사용하여 새 제품 생성

	// TODO: 초기 제품 정보 출력

	// TODO: 제품 재고를 보충하고 정보 출력

	// TODO: 판매를 시도하고 결과 출력
	// 판매가 성공하면 업데이트된 정보 출력
	// If sale fails, print "Sale failed: insufficient stock"

	fmt.Println() // 실제 출력으로 대체
}
quiz icon실력 점검

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

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

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