“静态类”或传递参考?

时间:2010-10-29 04:38:15

标签: java multithreading client-server

我是一个为客户/服务器模型海战视频游戏(大学课程)设计服务器的团队的一员。我们有一个相当具体的(我认为)系统设计,但有一个方面困扰我。

系统的基本布局是:

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)

现在,我的问题是Client和GameEvent(可能是环境,一旦我们到达它)需要引用它们所属的Game对象。

客户需要将GameEvent添加到Game的工作队列中。

GameEvent需要访问其他游戏数据(其他客户的船舶,环境)。

是否有更好/更传统的方法,而不是让这些对象存储他们的游戏的本地引用?将所有Game的方法声明为静态怎么样?我们一次只需要处理一个游戏,因此不会有多个游戏实例...

我确信有一个系统的约定,其中一个中心对象有许多需要引用它的辅助对象。

6 个答案:

答案 0 :(得分:3)

您是否考虑使用像Guice这样的依赖注入框架?在那里你有一个名为“modules”的配置类,你可以将你的界面Game绑定到一个实现(你可以决定你是否需要一个单例或新实例)。 Client类看起来像

public class Client {
   private final Game game;

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

   ... 
}

可以像往常一样构建这个类,提供一个Game实例(例如,使用模拟Game类进行测试)。但是如果你让Guice为你创建这个实例(不需要直接创建它,如果另一个类注入Client就行了),你会自动获得你的Guice模块中指定的实例。

我知道需要一些时间来围绕这个概念,但我可以确认这会导致更清晰,更灵活的代码。

答案 1 :(得分:1)

如果实际上只有逻辑一个实例,则可以使用单例。单身的规范形式是:

public enum Singleton {
    INSTANCE;

    // fields and methods here
}

这样,你就不必将所有东西都变成静态方法(但是,如果你想编写引用INSTANCE的静态方法,那也没关系)。任何想要访问单例的代码都只使用Singleton.INSTANCE,如果你不想,你不必传递它。

答案 2 :(得分:1)

传递引用将使您的选项保持打开状态,它仍然可以是对实际静态对象的引用。此外,请求上下文的概念可能很有用,该对象包含处理单个请求所需的所有引用,并且您可以传递它。

答案 3 :(得分:1)

查看控制反转(IOC)和容器。

这样,在您的Client和GameEvent课程中,只要您需要访问游戏,您就可以执行以下操作:

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

然后使用游戏实例方法......

答案 4 :(得分:1)

将引用传递给构造函数并存储它们没有任何问题。您还应该引入一个界面来调解您的游戏与客户端和环境对象之间的访问。

答案 5 :(得分:1)

我强烈建议您不要在设计中使用单例或静态类。这有很多原因,但最可能会立即影响到你的原因是它使测试变得非常困难。在测试时,可能会有多个Game实例。

改进一个具有大量辅助对象的大型中心对象的常见惯例是尝试避免一个大的中心对象。您注意到有不同的“游戏”客户有不同的需求。也许你的游戏界面太宽了。