Как связать две иерархии классов? Наверное, выраженный одним предложением, вопрос звучит дико. Попробую сформулировать понятнее. Игра разделена на некое подобие модели и представления. Имеется базовый класс для всех материальных объектов в игре: 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) {код инициализации}. Что скажете про такой вариант?
Опций решения данной проблемы несколько. Один из вариантов, который может быть элегантным и гибким, - использование шаблона проектирования "Фабрика".
Создайте интерфейс или абстрактный класс, например, SpaceObjectFactory, у которого будет метод CreateSpaceObject. Затем создайте конкретные фабрики для каждого типа SpaceObject (PlanetFactory, StarFactory, AsteroidFieldFactory и т.д.), которые будут реализовывать метод CreateSpaceObject и возвращать соответствующий объект типа SpaceObject.
При необходимости инициализации SpaceObject вызывайте метод InitializeSpaceObject, передавая объект фабрики, соответствующий типу SpaceObject. Таким образом, вы избавитесь от длинной цепочки if-else и сможете легко добавлять новые типы SpaceObject, просто создавая новую фабрику.
Этот подход поможет разделить логику создания объектов от их инициализации, делая код более удобным и расширяемым.
Опций решения данной проблемы несколько. Один из вариантов, который может быть элегантным и гибким, - использование шаблона проектирования "Фабрика".
Создайте интерфейс или абстрактный класс, например, SpaceObjectFactory, у которого будет метод CreateSpaceObject. Затем создайте конкретные фабрики для каждого типа SpaceObject (PlanetFactory, StarFactory, AsteroidFieldFactory и т.д.), которые будут реализовывать метод CreateSpaceObject и возвращать соответствующий объект типа SpaceObject.
При необходимости инициализации SpaceObject вызывайте метод InitializeSpaceObject, передавая объект фабрики, соответствующий типу SpaceObject. Таким образом, вы избавитесь от длинной цепочки if-else и сможете легко добавлять новые типы SpaceObject, просто создавая новую фабрику.
Этот подход поможет разделить логику создания объектов от их инициализации, делая код более удобным и расширяемым.