Как связать две иерархии классов? Наверное, выраженный одним предложением, вопрос звучит дико. Попробую сформулировать понятнее.
Игра разделена на некое подобие модели и представления. Имеется базовый класс для всех материальных объектов в игре: SpaceObject, у него есть наследники: Planet, Star, Ship, Asteroid и т.д.. Пока оно все "живет" внутри этой самой модели - все хорошо. Но как только возникает необходимость отобразить объект - появляются проблемы.
Итак, в случае, если объект появляется в одной локации с игроком (есть соответствующее событие), необходимо создать его "alter ego" в виде GameObject игрового движка. Проблема в таком коде:void InitializeSpaceObject(SpaceObject spaceObject)
{
if (spaceObject is Star)
InitializeStar(spaceObject as Star);
else if (spaceObject is Planet)
InitializePlanet(spaceObject as Planet);
else if (spaceObject is AsteroidField)
InitializeAsteroidField(spaceObject as AsteroidField);
else
throw new UnknownSpaceObjectTypeException("Cannot initialize SpaceObject of type " + spaceObject.GetType().ToString() + ": unknown type.");
}
Понятное дело, такой код, как минимум, нарушает принцип подстановки Лисков, а вообще - просто неудобен в использовании и расширении. Но просто добавить ссылку на некий инициализатор объекта в классе SpaceObject нельзя - модель не должна ничего знать о движке и всей логики визуализации.
Как можно избавиться от этой вереницы if'ов или, по крайней мере, автоматизировать процесс поиска инициализатора для нужного типа объекта?
Ниже попробую изложить пару вариантов, которые мне пришли в голову - возможно они жизнеспособны?
1)Объявить таблицу "Тип" - "Инициализатор". Чему быть инициализатором - делегатом метода или полноценным классом, вопрос уже вторичный. Немного лучше, чем if'ы, но все равно как-то громоздко
2)Unity-стайл. Создать по обычному MonoBehaviour скрипту на каждый тип объекта. Каждый слушает событие появления объекта в локации. Внутри подписанного метода - одна проверка if (spaceObject is ThisScriptHandlingType) {код инициализации}. Что скажете про такой вариант?

21 Авг 2019 в 07:05
204 +1
0
Ответы
1

Опций решения данной проблемы несколько. Один из вариантов, который может быть элегантным и гибким, - использование шаблона проектирования "Фабрика".

Создайте интерфейс или абстрактный класс, например, SpaceObjectFactory, у которого будет метод CreateSpaceObject. Затем создайте конкретные фабрики для каждого типа SpaceObject (PlanetFactory, StarFactory, AsteroidFieldFactory и т.д.), которые будут реализовывать метод CreateSpaceObject и возвращать соответствующий объект типа SpaceObject.

При необходимости инициализации SpaceObject вызывайте метод InitializeSpaceObject, передавая объект фабрики, соответствующий типу SpaceObject. Таким образом, вы избавитесь от длинной цепочки if-else и сможете легко добавлять новые типы SpaceObject, просто создавая новую фабрику.

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

20 Апр 2024 в 13:07
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир