2010-10-29 1 views
1

Я являюсь частью команды, проектирующей сервер для видеоигры типа «военный корабль» для клиентов и серверов (курс университета). У нас есть довольно конкретный (ну, я думаю) дизайн системы, но есть один аспект, который меня беспокоит.«статический класс» или передавать ссылки вокруг?

Базовая схема системы является:

Server [thread] (handles incoming connections) 
| 
Game [thread] (deals with game events in it's work queue and sending messages to clients) 
|--Environment (holds environment variables, deals with collision) 
|--Client(s) [thread] (handles incoming messages from client sockets and adds events to the Game's work queue) 
    |--Ship (holds game data, eg: hit points, fire power, etc) 
    |--Parser (parses client messages and creates game event objects) 
|--GameEvent (event objects held in a queue that can preform appropriate work and send appropriate responses to clients) 

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

Клиенты должны добавить GameEvent в рабочую очередь игры.

Необходимо, чтобы GameEvent нуждался в доступе к другим игровым данным (другим кораблям клиента, окружающей среде).

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

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

ответ

3

Считаете ли вы использование инфраструктуры для инъекций зависимостей, таких как Guice? Там у вас есть классы конфигурации, называемые «modules», где вы привязываете свой интерфейс Game к реализации (вы можете решить, хотите ли вы одиночный или новый экземпляр). Класс клиента будет выглядеть

public class Client { 
    private final Game game; 

    @Inject 
    public Client(Game game) { 
     this.game = game; 
    } 

    ... 
} 

Тобой можно построить этот класс, как обычно, обеспечивая экземпляр игры (например, для тестирования, используя макет класса Game). Но если вы позволите Guice создать этот экземпляр для вас (который не обязательно должен быть напрямую, он также работает, если другой класс вводит Client), вы автоматически получаете экземпляр, указанный в вашем модуле Guice.

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

+1

+1 Инъекционная инъекция - хорошая идея, хотя вы должны называть ее не только ДИ. OP все еще студент, и многие студенты, вероятно, не слышали о таких вещах, как инъекция зависимостей и инверсия контроля. :-P –

+0

Изменено. Благодаря! – Landei

1

Если есть действительно только логически один экземпляр, вы можете использовать singleton. Каноническая форма Синглтон:

public enum Singleton { 
    INSTANCE; 

    // fields and methods here 
} 

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

+1

Осторожно ... Синглтон считается многими непротиворечивыми: http://www.google.com/search?q=singleton+antipattern – Guillaume

+0

@Guillaume: В самом деле, лучше не быть слишком хун-хо о используя синглтоны, хотя есть время и место для них (объекты функции без состояния, являющегося моим текущим любимым примером). Зная, когда ваша ситуация такая, или нет, это вопрос в миллион долларов. –

1

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

1

Проверьте инверсию управления (МОК) и контейнеры.

Таким образом, в вашем клиенте и GameEvent классов, когда вам нужен доступ к игре, вы просто сделать что-то вроде:

var game = IoC.Resolve<Game>(); 

И затем использовать методы экземпляра игры ...

+0

Мне интересно, что там наверху. Является ли Resolve достаточно быстрым, чтобы называться миллионами раз в секунду, или это будет забивать вещи? –

+0

Вы не вызываете решение более одного раза в классе, где вам это нужно ... – GalacticJello

+0

Это Java, а не C#. Вы не получаете таких тонкостей, как 'IoC.Resolve ()'; в лучшем случае вы можете использовать 'IoC.resolve (Game.class)'. :-) (Java имеет стили, основанные на стирании: параметры типа не будут доступны во время выполнения.) –

1

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

+0

Я не совсем понимаю, что вы имеете в виду, но если я понимаю, это была точка использования очереди для игрового события. Что именно вы подразумеваете под интерфейсом для посредничества в доступе? –

1

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

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

+0

Я так не думаю. Дело в том, что мне нужен какой-то объект для обработки клиентских запросов (сообщений, например: changeSpeed). Учитывая многопоточный подход, мы решили, что очередь будет иметь смысл избежать проблем с параллелизмом. Весь наш игровой объект когда-либо будет делать, это спросить GameEvent в очереди, чтобы выполнить свою работу и отправить соответствующее сообщение для клиентов. Игра на самом деле не «большая», просто это где-то, должен быть корневой узел, который все объекты игры могут использовать для ссылки на другие объекты игры. Похоже, что прохождение ссылок вокруг - лучший вариант. –

+0

Извините, просто примечание по вышесказанному: игра не обрабатывает сами клиентские сокеты, просто объекты GameEvent в очереди, которые были проанализированы и предложены объектами Client. –

Смежные вопросы