Menu
Coddy logo textTech

Геттеры и сеттеры

Часть раздела Объектно-ориентированное программирование путешествия по 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 действует как специализированный сеттер, который обеспечивает соблюдение правил — отрицательные депозиты не допускаются. Внешний код должен обращаться через ваши методы, гарантируя, что структура всегда остается в валидном состоянии. Это инкапсуляция в действии: скрытие данных при предоставлении контролируемого поведения.

challenge icon

Задание

Легко

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

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

  • temperature.go: Создайте структуру Temperature с неэкспортируемым полем celsius (float64). Реализуйте следующие методы:
    • Celsius() — геттер, который возвращает текущую температуру в градусах Цельсия
    • SetCelsius(value float64) — сеттер, который принимает значения только не ниже абсолютного нуля (-273.15). Если значение ниже этого порога, температура должна остаться неизменной.
    • Fahrenheit() — возвращает температуру, преобразованную в градусы Фаренгейта по формуле: (celsius * 9/5) + 32
    • SetFahrenheit(value float64) — преобразует входное значение из Фаренгейтов в Цельсии и сохраняет его, но только если полученное значение в Цельсиях не ниже -273.15
    Также добавьте конструктор NewTemperature(celsius float64) *Temperature, который создает температуру, инициализированную заданным значением (предполагается, что для конструктора вводятся корректные данные).
  • main.go: Считайте значения температуры из входных данных и продемонстрируйте работу методов геттеров/сеттеров. Создайте объект температуры, выведите его значения в обеих единицах измерения, затем попытайтесь установить новые значения и покажите результаты.

Будут предоставлены следующие входные данные:

  • Строка 1: Начальное значение в Цельсиях
  • Строка 2: Новое значение в Цельсиях для установки
  • Строка 3: Новое значение в Фаренгейтах для установки

Форматируйте все выводы температуры с двумя знаками после запятой. Выведите следующую последовательность:

  1. После создания: C: [celsius] F: [fahrenheit]
  2. После установки Цельсия: C: [celsius] F: [fahrenheit]
  3. После установки Фаренгейта: 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). В этом и заключается сила сеттеров — они обеспечивают соблюдение правил, которые поддерживают корректность ваших данных.

Шпаргалка

Неэкспортируемые поля требуют методов getter (геттер) и setter (сеттер) для контролируемого доступа извне пакета.

Соглашение о геттерах

В Go геттеры используют имя поля с заглавной первой буквы. Не добавляйте префикс "Get":

type BankAccount struct {
    balance int  // неэкспортируемое
}

// Getter - возвращает значение
func (b *BankAccount) Balance() int {
    return b.balance
}

Сеттер с валидацией

Сеттеры изменяют значения и могут включать валидацию или бизнес-логику:

// Setter - изменяет значение с валидацией
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
}

Этот подход обеспечивает инкапсуляцию: скрытие данных при предоставлении контролируемого поведения, что поддерживает структуры в валидном состоянии.

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

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

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

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