Hero background image
Как использовать паттерн фабрики для создания объектов во время выполнения программы

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

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

На этой странице рассказывается о шаблоне проектирования фабрики.

Содержание этой статьи основано на бесплатной электронной книге, Повысьте уровень своего кода с помощью паттернов программирования игр.

Ознакомьтесь с другими статьями из серии "Шаблоны проектирования игрового программирования Unity" на хабе " Лучшие практики Unity " или по этим ссылкам:

Заводская схема
МОДЕЛЬ ПРОЕКТИРОВАНИЯ "ФАБРИКА" ПРЕДОСТАВЛЯЕТ ИНТЕРФЕЙС ДЛЯ СОЗДАНИЯ ОБЪЕКТОВ В СУПЕРКЛАССЕ, НО ПОЗВОЛЯЕТ ПОДКЛАССАМ ИЗМЕНЯТЬ ТИП СОЗДАВАЕМЫХ ОБЪЕКТОВ
Понимание шаблона фабрики

Иногда полезно иметь специальный объект, который создает другие объекты. Многие игры порождают множество вещей в течение игрового процесса, и вы часто не знаете, что вам нужно во время выполнения, пока это не понадобится на самом деле.

В паттерне фабрики для этой цели предназначен специальный объект, называемый - вы уже догадались - фабрикой. С одной стороны, в нем заключены многие детали, связанные с порождением его "продуктов". Непосредственным преимуществом является уменьшение объема кода.

Однако если каждый продукт следует общему интерфейсу или базовому классу, вы можете пойти дальше и сделать так, чтобы он содержал больше собственной логики построения, скрывая ее от самой фабрики. Таким образом, создание новых объектов становится более расширяемым.

Вы также можете подклассифицировать фабрику, чтобы создать несколько фабрик, предназначенных для определенных продуктов. Это помогает генерировать врагов, препятствия или что-то еще во время выполнения.

Образцовый проект фабрики
ОДИН ПРОДУКТ ВОСПРОИЗВОДИТ ЗВУК, А ДРУГОЙ - ЧАСТИЦЫ. ОБА ИСПОЛЬЗУЮТ ОДИН И ТОТ ЖЕ ИНТЕРФЕЙС.
Тестирование шаблона завода в примере проекта

На GitHub доступен пример проекта, демонстрирующий различные паттерны программирования в контексте разработки игр, в том числе паттерн фабрики.

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

Заводская сцена находится в папке "6 Factory".

Создание простой фабрики

Представьте, что вы хотите создать паттерн фабрики для создания элементов для игрового уровня. Вы можете использовать префабы для создания игровых объектов, но, возможно, вам также захочется запускать пользовательское поведение при создании каждого экземпляра.

Вместо того чтобы использовать операторы if или switch для поддержания этой логики, создайте интерфейс IProduct и абстрактный класс Factory, как показано в примере кода.

Продукты должны следовать определенному шаблону для своих методов, но в остальном они не имеют общей функциональности. Таким образом, вы определяете интерфейс IProduct.

Фабрикам может потребоваться некоторая общая функциональность, поэтому в данном примере используются абстрактные классы. Только не забывайте о подстановке Лискова из принципов SOLID при использовании подклассов. Он гласит, что объекты суперкласса должны быть заменяемы объектами подкласса без ущерба для корректности программы. Другими словами, любая программа, использующая ссылку на суперкласс, должна иметь возможность использовать любой из его подклассов, не зная об этом.

ИСПОЛЬЗОВАНИЕ ИНТЕРФЕЙСА ДЛЯ ОПРЕДЕЛЕНИЯ ОБЩИХ СВОЙСТВ И ЛОГИКИ МЕЖДУ ВАШИМИ ПРОДУКТАМИ
ИСПОЛЬЗОВАНИЕ ИНТЕРФЕЙСА ДЛЯ ОПРЕДЕЛЕНИЯ ОБЩИХ СВОЙСТВ И ЛОГИКИ МЕЖДУ ВАШИМИ ПРОДУКТАМИ
Структура классов в паттерне фабрики

Интерфейс IProduct определяет то, что является общим для ваших продуктов. В этом случае у вас просто есть свойство ProductName и любая логика продукта, выполняемая при Initialize.

Затем вы можете определить столько продуктов, сколько вам нужно(ProductA, ProductB и т.д.), если они соответствуют интерфейсу IProduct.

В базовом классе Factory есть метод GetProduct, который возвращает IProduct. Он абстрактный, поэтому вы не можете создавать экземпляры Factory напрямую. Вы создаете пару конкретных подклассов(ConcreteFactoryA и ConcreteFactoryB), которые, собственно, и будут получать различные продукты.

GetProduct в этом примере принимает позицию Vector3, чтобы вам было проще инстанцировать объект Prefab GameObject в определенном месте. В поле каждой бетонной фабрики также хранится соответствующий шаблон Prefab.

В результате получается структура, похожая на изображение выше.

Пример кода

В фрагменте кода вы можете увидеть пример ProductA и ConcreteFactoryA.

Здесь вы заставили классы продуктов MonoBehaviours, реализующие IProduct, использовать преимущества префабов на фабрике.

Обратите внимание, что каждый продукт может иметь свою собственную версию Initialize. Пример префаба ProductA содержит ParticleSystem, который воспроизводится, когда ConcreteFactoryA создает его копию. Сама фабрика не содержит никакой особой логики для запуска частиц; она только вызывает метод Initialize, который является общим для всех продуктов.

Изучите пример проекта, чтобы увидеть, как компонент ClickToCreate переключается между фабриками для создания ProductA и ProductB, которые имеют разное поведение. Продукт B воспроизводит звук при появлении, а продукт A запускает эффект частиц, чтобы проиллюстрировать основную концепцию вариаций продуктов.

Плюсы и минусы

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

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

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

Адаптация заводского шаблона

Реализация фабрики может сильно отличаться от того, что показано здесь. При построении собственной фабричной выкройки учитывайте следующие корректировки:

Используйте словарь для поиска товаров: Возможно, вы захотите хранить свои продукты в виде пар ключ-значение в словаре. В качестве ключа используйте уникальный строковый идентификатор (например, Имя или какой-либо идентификатор), а в качестве значения - тип. Это может сделать поиск продуктов и/или соответствующих им фабрик более удобным.

Сделайте фабрику (или менеджера фабрики) статичной: Это упрощает использование, но требует дополнительных настроек. Статические классы не будут отображаться в Инспекторе, поэтому вам нужно сделать коллекцию продуктов также статической.

Примените его к неигровым объектам и немонобъектам: Не ограничивайте себя префабами или другими компонентами, специфичными для Unity. Шаблон фабрики может работать с любым объектом C#.

Комбинируйте с шаблоном "Пул объектов": Фабрики не обязательно должны инстанцировать или создавать новые объекты. Они также могут извлекать существующие в иерархии. Если вы инстанцируете сразу много объектов (например, снаряды из оружия), используйте паттерн пула объектов для более оптимизированного управления памятью.

Фабрики могут порождать любой игровой элемент по мере необходимости. Однако создание продуктов часто не является их единственной целью. Возможно, вы используете паттерн фабрики как часть другой более крупной задачи (например, настройка элементов пользовательского интерфейса в диалоговом окне части игрового уровня).

Запись в блоге
Дополнительные ресурсы

Дополнительные советы по использованию паттернов проектирования в приложениях Unity, а также принципы SOLID вы найдете в бесплатной электронной книге Level up your code with game programming patterns.

Все передовые технические электронные книги и статьи по Unity можно найти в хабе лучших практик. Электронные книги также доступны на странице " Передовые методы" в документации.

Понравился ли вам этот контент?