Доступ через замыкания
Часть раздела Объектно-ориентированное программирование путешествия по Lua на Coddy. Урок 45 из 70.
Private local переменные бесполезны, если вы никогда не можете взаимодействовать с ними. Решение — определить getter и setter methods inside constructor, где у них есть доступ к области видимости closure.
Поскольку эти methods создаются inside :new(), они могут «видеть» local переменные. Вы назначаете их directly объекту:
local Counter = {}
Counter.__index = Counter
function Counter:new()
local count = 0 -- Приватная переменная
local obj = {}
-- Определить методы внутри конструктора
function obj:getCount()
return count
end
function obj:increment()
count = count + 1
end
setmetatable(obj, Counter)
return obj
endТеперь к закрытой переменной count можно получить доступ, но только через предоставленные вами methods:
local c = Counter:new()
print(c:getCount()) -- 0
c:increment()
c:increment()
print(c:getCount()) -- 2
print(c.count) -- nil (всё ещё скрыто!)Обратите внимание, что :getCount() и :increment() определены непосредственно на obj, а не в таблице класса. Каждый экземпляр получает собственную копию этих функций, каждая из которых имеет доступ к своему собственному приватному count. Такова цена: настоящая приватность требует немного больше памяти, поскольку methods не являются общими через прототип.
Задание
ЛегкоДавайте создадим класс Temperature, который использует приватность на основе замыкания для хранения значения температуры в градусах Цельсия, а методы getter и setter, определённые внутри constructor, обеспечивают контролируемый доступ!
Вы организуете код в двух файлах:
Temperature.lua: Создайте class, в котором значение температуры хранится в локальной переменной внутри constructor: оно полностью скрыто от внешнего доступа. Constructor:new(initialCelsius)должен сохранить температуру в локальной переменной, а затем определить следующие methods непосредственно в instance объекта::getCelsius(): возвращает текущую температуру в градусах Цельсия:setCelsius(value): изменяет температуру на новое значение:getFahrenheit(): возвращает температуру, converted в градусы Фаренгейта, используя Formula:(celsius * 9/5) + 32
main.lua: Require ваш модуль Temperature и считайте два значения из input: initial температуру и новую температуру для установки. Create instance Temperature с initial значением, выведите показания в градусах Цельсия и Фаренгейта, затем используйте setter, чтобы изменить температуру, и снова выведите оба показания.
Вы получите два входных значения:
- Начальная температура в градусах Цельсия (число)
- Новая температура для установки (число)
Ваш вывод должен содержать четыре строки с показаниями температуры до и после change:
Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}Например, если входными значениями являются 0 и 100, вывод должен быть таким:
Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212Помните: значение температуры должно храниться в локальной переменной внутри :new(), а не в self. Getter и setter methods определяются внутри constructor, где они могут получить доступ к этой private переменной через closure. Попытка напрямую обратиться к temp.celsius или temp._celsius должна возвращать nil!
Попробуйте сами
-- Подключить модуль Temperature
local Temperature = require('Temperature')
-- Прочитать входные значения
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())
-- TODO: Создать экземпляр Temperature с начальным значением
-- TODO: Вывести начальные показания Celsius и Fahrenheit
-- TODO: Использовать сеттер, чтобы изменить температуру на newTemp
-- TODO: Вывести обновлённые показания Celsius и Fahrenheit
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигурПотренируйтесь самостоятельно: Онлайн-компилятор Lua