Menu
Coddy logo textTech

Сокрытие информации в Go

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 50 из 107.

Скрытие информации выходит за рамки простого объявления полей неэкспортируемыми. Речь идет о проектировании ваших типов таким образом, чтобы внешний код знал только то, что ему необходимо знать, и ничего больше.

Цель состоит в том, чтобы предоставить доступ к поведению через методы, сохраняя при этом внутреннюю структуру полностью скрытой. Рассмотрим этот подход:

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, — при условии, что методы ведут себя так же.

Этот принцип также применим к вспомогательным функциям. Оставляйте внутреннюю логику неэкспортируемой:

// Экспортируемая - часть публичного API
func (c *Counter) Reset() {
    c.value = 0
}

// неэкспортируемая - внутренний помощник
func (c *Counter) isAtLimit() bool {
    return c.value >= c.maxLimit
}

Скрывая isAtLimit(), вы можете свободно изменять или удалять его позже. Сокрытие информации создает четкую границу между тем, что ваш пакет обещает внешним пользователям, и тем, как он работает внутри.

challenge icon

Задание

Легко

Давайте создадим систему безопасного кошелька, которая демонстрирует сокрытие информации. Вы создадите цифровой кошелек, в котором внутреннее отслеживание баланса и история транзакций полностью скрыты от внешнего кода — наружу через методы выставляется только поведение.

Вы организуете свой код в двух файлах:

  • wallet.go: Создайте структуру Wallet, которая скрывает все свое внутреннее состояние. Кошелек должен внутренне отслеживать текущий баланс и лимит расходов, но внешний код никогда не должен знать, как они хранятся или представлены. Предоставьте поведение через следующие методы:
    • NewWallet(limit float64) *Wallet - конструктор, который создает кошелек с заданным лимитом расходов и нулевым балансом
    • 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 — даже несмотря на то, что баланса достаточно. Кошелек применяет свои правила внутренне, не раскрывая, как он принимает эти решения. Внешний код просто вызывает методы и получает результаты, никогда не зная деталей внутренней реализации.

Попробуйте сами

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: Выполнить второй расход и вывести результат
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование