Это плохая идея иметь статическую игру Game1 в XNA?


10

Это действительно плохая идея, чтобы мой Game1класс был статичным? На данный момент в моем Game1классе есть класс, TileHandlerкоторый обрабатывает все, что связано с моим текущим набором плиток, и AnimalHandlerкоторый обрабатывает всех моих животных (удивительно).

Теперь, если я вхожу AnimalHandlerи хочу проверить, пригодна TileHandlerли для прохода плитка, то это вызывает проблемы, или я должен передать список пригодных для прохода плиток AnimalHandler, что я бы предпочел не делать.

Что было бы проще, так это сделать Game1статичным, а затем AnimalHandlerпросто начать Game1._tileHandler.WalkableTile(position).

Сейчас я не вижу в этом ничего плохого или такого, что могло бы вызвать какие-либо проблемы, но я только начал использовать статические классы, поэтому кто-нибудь более знающий видит какую-то гигантскую причину, почему это плохая идея?

Ответы:


9

Сейчас я не вижу в этом ничего плохого или такого, что могло бы вызвать какие-либо проблемы, но я только начал использовать статические классы, поэтому кто-нибудь более знающий видит какую-то гигантскую причину, почему это плохая идея?

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

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

Вот суть вашей проблемы:

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

Игнорирование возможности того, что AnimalHandlerэти плитки сами по себе могут быть плохим дизайном (с выбранными вами именами, трудно сказать подробности этих классов) на данный момент ... если AnimalHandlerнужен список ходовых плиток, то ему нужен список прогулочные плитки. Как правило, лучше сделать зависимости более явными, чем менее, так как это делает код более самодокументированным. Передав список напрямую AnimalHandler, вы явно указываете, что ему нужен такой список. Если вместо этого вы сделаете все статичным и общедоступным, чтобы вы могли просто получить доступ к статическому списку, хранящемуся в другом месте кода, все, что вам нужно сделать, - это скрыть зависимость, фактически не решая и не удаляя ее.

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


Аминь! Вы затронули замечательный момент, о котором я не говорил в своем ответе.
Nate

+1 Сокрытие зависимостей и представление глобального состояния - это действительно проблема здесь
ashes999

4

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

Если в будущем вы решите использовать несколько TileHandler, вам придется проделать большую работу, чтобы учесть это изменение.

Если вы решите удалить TileHandler, вам придется проделать большую работу, чтобы учесть это изменение.

Предположим, что в будущем вы создадите другой уровень / зону, который будет обрабатывать плитки не так, как ваш текущий TileHandler. Затем вам нужно либо указать способ использования плитки, либо вызвать другой обработчик.

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

Лично я получаю доступ ко многим вещам в моих играх XNA из статического контекста и предполагаю, что у меня никогда не будет больше одной из них.

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

Короче говоря:

В пользу не использования статического контекста:

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

В пользу статического контекста:

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


2

Я не думаю, что это очень плохая идея для простой игры, но вы также можете взглянуть на http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services для лучшая идея о том, как создавать взаимосвязанные игровые компоненты


Не могли бы вы подумать о проблемах, если бы это была не простая игра?
Гарольд

Читаемость кода, тестируемость и хорошие методы архитектуры предложили бы избежать этого.
smnbss

2

Такие вещи, как TileHandler и AnimalHandler, я бы поднял уровень на экране игры. Нужен ли вашему экрану заголовка доступ к TileHandler и инициализируется ли он при первой загрузке игры? Возможно нет.

Проверьте образец XNA State Management . Там много кода, но в основном базовая игра просто инициализирует стек игровых состояний (или экранов). Каждый экран довольно независим от других и работает как упрощенная версия самой игры. Ваш PlayScreen может иметь статические элементы, поэтому они доступны для компонентов PlayScreen.

В базовой игре я использую немного статики, но это вещи очень низкого уровня, такие как InputHelper, Log или Config reader. Они довольно стандартны во всех играх, поэтому базовый движок можно легко и быстро перенести. На экранах происходит настоящая игровая логика. Так что длинный ответ короткий - нет, я не думаю, что это плохая идея в теории, просто будьте осторожны с тем, что вы делаете статичным. Когда вы делаете что-то статичное, это огромная работа, если вы передумаете.


0

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

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

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


0

Да, это вообще всегда плохая идея.

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

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

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

  3. Это скрывает зависимости. Подобно анти-шаблону поставщика услуг (также используемому в XNA, Game.Services), ваши классы могут выбирать зависимости, которые вы не видите снаружи.

Этот подход становится особенно ядовитым, если объединить статические классы с вызовами грузовых поездов (вещи, такие как Game.Instance.ActorManager.Enemies.FindInRange(10)так называемые цепные символы, похожие на вагоны), где компонентам внезапно требуется не только Gameкласс, но и класс со статическим Instanceсвойством, которое возвращает что-то с ActorManagerсвойство , которое имеет Enemiesсвойство , которое возвращает объект с FindInRange()методом.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.