Java &引用;“静态类”;或者传递参考资料?

Java &引用;“静态类”;或者传递参考资料?,java,multithreading,client-server,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 environm

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

系统的基本布局为:

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需要访问其他游戏数据(其他客户端的船只、环境)

有没有更好/更传统的方法来代替让这些对象存储对其游戏的本地引用?把游戏的所有方法都声明为静态的怎么样?我们一次只需要处理一个游戏,所以不会有超过一个游戏实例


我确信对于一个具有一个中心对象的系统来说,有一个约定,其中有许多需要引用它的helper对象。

如果在逻辑上只有一个实例,那么可以使用单实例。单例的标准形式是:

public enum Singleton {
    INSTANCE;

    // fields and methods here
}

这样,您就不必把所有内容都塞进静态方法中(不过,如果您想编写引用
实例
的静态方法,也可以)。任何想要访问单例的代码都只使用
singleton.INSTANCE
,如果不想,您不必传递它。

如果在逻辑上只有一个实例,您可以使用单例。单例的标准形式是:

public enum Singleton {
    INSTANCE;

    // fields and methods here
}

这样,您就不必把所有内容都塞进静态方法中(不过,如果您想编写引用
实例
的静态方法,也可以)。任何想要访问单例的代码都只使用
singleton.INSTANCE
,如果不想,您不必传递它。

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

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

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

这样,在客户端和GameEvent类中,每当需要访问游戏时,您只需执行以下操作:

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

然后使用游戏实例方法…

检查控制反转(IOC)和容器

这样,在客户端和GameEvent类中,每当需要访问游戏时,您只需执行以下操作:

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

然后使用游戏实例方法…

将引用传递给构造函数并存储它们没有错。您还应该引入一个接口,该接口将在您的游戏、客户端和环境对象之间调解访问。

将引用传递给构造函数并存储它们没有什么错。您还应该引入一个接口,该接口将在您的游戏、客户端和环境对象之间进行中介访问。

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


改进一个大的中心对象和许多辅助对象的常用约定是尽量避免使用一个大的中心对象。您注意到“游戏”的不同客户有不同的需求。可能游戏界面太宽了。

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


改进一个大的中心对象和许多辅助对象的常用约定是尽量避免使用一个大的中心对象。您注意到“游戏”的不同客户有不同的需求。也许你的游戏界面太宽了。

< P>你是否考虑过使用Guice之类的依赖注入框架?在这里,您有一个名为“modules”的配置类,您可以将界面游戏绑定到一个实现(您可以决定是想要一个单实例还是新实例)。客户端类看起来像

public class Client {
   private final Game game;

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

   ... 
}
您可以像往常一样构造这个类,提供一个游戏实例(例如,为了测试,使用模拟游戏类)。但是,如果让Guice为您创建这个实例(不需要直接创建,如果另一个类注入了客户机,它也可以工作),那么您将自动获得Guice模块中指定的实例


我知道这需要一些时间来理解这个概念,但我可以确认,这将导致更干净、更灵活的代码

>你考虑过使用Guice之类的依赖注入框架吗?在这里,您有一个名为“modules”的配置类,您可以将界面游戏绑定到一个实现(您可以决定是想要一个单实例还是新实例)。客户端类看起来像

public class Client {
   private final Game game;

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

   ... 
}
您可以像往常一样构造这个类,提供一个游戏实例(例如,为了测试,使用模拟游戏类)。但是,如果让Guice为您创建这个实例(不需要直接创建,如果另一个类注入了客户机,它也可以工作),那么您将自动获得Guice模块中指定的实例

我知道这需要一些时间来理解这个概念,但我可以确认,这将导致更干净、更灵活的代码

我想知道w