Фабричные функции
Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 62 из 70.
На протяжении этого курса вы создавали объекты, вызывая конструкторы напрямую — Circle:new(), Rectangle:new() и так далее. Но что, если вы хотите создавать различные типы объектов на основе некоторого условия, при этом вызывающему коду не нужно знать, какой именно класс использовать?
Вот здесь на помощь приходит паттерн «Фабрика» (Factory pattern). Фабрика — это просто функция, которая создает и возвращает объекты. Ключевое преимущество заключается в том, что вызывающей стороне не нужно знать детали создания объекта — она просто запрашивает у фабрики то, что ей нужно.
local function createShape(shapeType)
if shapeType == "circle" then
return Circle:new(10)
elseif shapeType == "square" then
return Square:new(5)
end
end
-- Вызывающему коду не нужно знать о классах Circle или Square
local myShape = createShape("circle")
print(myShape:area())
Фабричная функция принимает строковый аргумент и решает, какой класс инстанцировать. Это централизует логику создания объектов в одном месте. Если позже вы добавите новый тип фигуры, вам нужно будет изменить только фабрику, а не каждый фрагмент кода, создающий фигуры.
Фабрики особенно полезны, когда создание объектов включает сложную настройку, когда вы хотите скрыть детали реализации или когда точный тип объекта зависит от условий времени выполнения, таких как пользовательский ввод или конфигурационные файлы.
Задание
ЛегкоДавайте создадим Фабрику Питомцев! Вместо того чтобы создавать питомцев напрямую, вызывая конструктор каждого класса, вы создадите функцию-фабрику, которая производит нужный тип питомца на основе простого строкового аргумента.
Вы организуете свой код в четырех файлах:
Dog.lua: Создайте класс Dog с конструктором:new(name), который сохраняет имя питомца. Добавьте метод:speak(), который возвращает строку"{name} says: Woof!"(где {name} — это имя собаки).Cat.lua: Создайте класс Cat с такой же структурой — конструктором:new(name)и методом:speak(), который возвращает"{name} says: Meow!".PetFactory.lua: Здесь паттерн «Фабрика» проявляет себя во всей красе! Создайте функциюcreatePet(petType, name), которая принимает два аргумента: строку, указывающую тип питомца ("dog"или"cat"), и имя питомца. Функция должна возвращать соответствующий объект питомца. Если тип —"dog", верните новый объект Dog; если"cat"— новый объект Cat.main.lua: Подключите модуль PetFactory. Прочитайте два входных значения: тип питомца и его имя. Используйте функцию фабрики для создания питомца, затем вызовите его метод:speak()и выведите результат.
Прелесть паттерна «Фабрика» заключается в том, что вашему основному коду не нужно напрямую подключать Dog или Cat — он знает только о фабрике. Фабрика берет на себя все детали того, какой класс нужно инстанцировать.
Вы получите два входных значения:
- Тип питомца (либо
"dog", либо"cat") - Имя питомца (строка)
Например, если на вход подаются dog и Buddy, результат должен быть:
Buddy says: Woof!Если на вход подаются cat и Whiskers, результат должен быть:
Whiskers says: Meow!Шпаргалка
Паттерн Фабрика (Factory pattern) — это паттерн проектирования, в котором функция создает и возвращает объекты на основе заданных параметров. Вызывающей стороне не нужно знать, какой именно класс создается — фабрика берет это решение на себя.
Фабричная функция централизует логику создания объектов:
local function createShape(shapeType)
if shapeType == "circle" then
return Circle:new(10)
elseif shapeType == "square" then
return Square:new(5)
end
end
local myShape = createShape("circle")
print(myShape:area())
Преимущества паттерна Фабрика:
- Скрывает детали реализации от вызывающей стороны
- Централизует создание объектов в одном месте
- Позволяет легко добавлять новые типы — изменения требуются только в самой фабрике
- Полезен, когда тип объекта зависит от условий времени выполнения (ввод пользователя, конфигурация и т. д.)
- Помогает, когда создание объекта требует сложной настройки
Попробуйте сами
-- main.lua
-- Используйте PetFactory для создания питомцев
local PetFactory = require('PetFactory')
-- Чтение входных данных
local petType = io.read()
local petName = io.read()
-- TODO: Используйте PetFactory.createPet для создания питомца
-- TODO: Вызовите метод :speak() питомца и выведите результат
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур