Геттеры и сеттеры
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 49 из 107.
Поскольку неэкспортируемые поля не могут быть доступны напрямую извне пакета, вам необходимо предоставить методы, обеспечивающие контролируемый доступ. Их обычно называют геттерами и сеттерами.
В Go соглашение для геттеров простое: используйте имя поля с заглавной первой буквы. Не добавляйте префикс «Get» — просто используйте Balance(), а не GetBalance():
type BankAccount struct {
balance int // неэкспортируемое
}
// Геттер — возвращает значение
func (b *BankAccount) Balance() int {
return b.balance
}
// Сеттер — изменяет значение с валидацией
func (b *BankAccount) SetBalance(amount int) {
if amount >= 0 {
b.balance = amount
}
}
Настоящая мощь сеттеров заключается в добавлении валидации или бизнес-логики. Вместо того чтобы позволять внешнему коду устанавливать любое значение напрямую, вы контролируете то, что разрешено:
func (b *BankAccount) Deposit(amount int) bool {
if amount <= 0 {
return false
}
b.balance += amount
return true
}
Этот метод Deposit действует как специализированный сеттер, который обеспечивает соблюдение правил — отрицательные депозиты не допускаются. Внешний код должен обращаться через ваши методы, гарантируя, что структура всегда остается в валидном состоянии. Это инкапсуляция в действии: скрытие данных при предоставлении контролируемого поведения.
Задание
ЛегкоДавайте создадим конвертер температуры, который демонстрирует правильную инкапсуляцию с использованием методов геттеров и сеттеров. Вы создадите структуру, которая хранит температуру внутри в градусах Цельсия, но обеспечивает контролируемый доступ через методы с валидацией.
Вы организуете свой код в двух файлах:
temperature.go: Создайте структуруTemperatureс неэкспортируемым полемcelsius(float64). Реализуйте следующие методы:Celsius()— геттер, который возвращает текущую температуру в градусах ЦельсияSetCelsius(value float64)— сеттер, который принимает значения только не ниже абсолютного нуля (-273.15). Если значение ниже этого порога, температура должна остаться неизменной.Fahrenheit()— возвращает температуру, преобразованную в градусы Фаренгейта по формуле:(celsius * 9/5) + 32SetFahrenheit(value float64)— преобразует входное значение из Фаренгейтов в Цельсии и сохраняет его, но только если полученное значение в Цельсиях не ниже -273.15
NewTemperature(celsius float64) *Temperature, который создает температуру, инициализированную заданным значением (предполагается, что для конструктора вводятся корректные данные).main.go: Считайте значения температуры из входных данных и продемонстрируйте работу методов геттеров/сеттеров. Создайте объект температуры, выведите его значения в обеих единицах измерения, затем попытайтесь установить новые значения и покажите результаты.
Будут предоставлены следующие входные данные:
- Строка 1: Начальное значение в Цельсиях
- Строка 2: Новое значение в Цельсиях для установки
- Строка 3: Новое значение в Фаренгейтах для установки
Форматируйте все выводы температуры с двумя знаками после запятой. Выведите следующую последовательность:
- После создания:
C: [celsius] F: [fahrenheit] - После установки Цельсия:
C: [celsius] F: [fahrenheit] - После установки Фаренгейта:
C: [celsius] F: [fahrenheit]
Например, при вводе 25, -300 и 212, ваш вывод должен быть:
C: 25.00 F: 77.00
C: 25.00 F: 77.00
C: 100.00 F: 212.00Обратите внимание, что вторая строка показывает неизменные значения, потому что -300 ниже абсолютного нуля, поэтому сеттер отклонил его. Третья строка показывает температуру после успешной установки 212°F (что соответствует 100°C). В этом и заключается сила сеттеров — они обеспечивают соблюдение правил, которые поддерживают корректность ваших данных.
Попробуйте сами
package main
import (
"fmt"
)
func main() {
// Считать входные значения
var initialCelsius float64
var newCelsius float64
var newFahrenheit float64
fmt.Scanln(&initialCelsius)
fmt.Scanln(&newCelsius)
fmt.Scanln(&newFahrenheit)
// TODO: Создать новый объект Temperature, используя конструктор
// TODO: Вывести начальные значения в формате "C: [celsius] F: [fahrenheit]" с 2 знаками после запятой
// TODO: Попытаться установить новое значение Цельсия и вывести результат
// TODO: Попытаться установить новое значение Фаренгейта и вывести результат
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker PoolПотренируйтесь самостоятельно: Онлайн-компилятор Go