需要一种优雅的方式来在指定的时间间隔内调用任意代码

时间:2009-03-30 18:08:33

标签: java design-patterns quartz-scheduler

好的,我有一个用Java / Hibernate / Spring / Quartz运行的游戏服务器。游戏时钟用石英计时器打勾,效果很好。

但是,我还有许多其他事情需要以特定的,可调整的间隔(在游戏时间,而不是实时)发生。

例如,每24小时游戏时间(约47分钟的实时时间,取决于服务器时钟倍频),会发生一系列不同的每日一次的游戏动作,例如补给,或者你有什么。

现在,当前的系统非常粗糙,但是有效 - 我在数据库中有一个表,它本质上是一个cron - 一个字符串键,下一个事件的执行时间,然后是小时,分钟,秒和天,直到下一个一个之后。时间标记器检查该标记,然后将包含该代码(事件字符串键)的消息发送到队列,将日期,分钟,秒添加到当前时间并将其设置为下一个执行时间。

消息监听器是grody部分 - 它打开密钥并点击其中一个方法。

现在我明白这可以正常工作,但它确实不适合我。你的解决方案是什么,将每一段代码放在自己的小班中?什么设计模式涵盖了这个? (我确定有一个)。我有一些想法,但我想听听一些意见。

5 个答案:

答案 0 :(得分:1)

您可以将代码用作映射中的键,而不是切换一组代码,其中值是实现处理程序接口的对象。这使您可以更灵活地添加新事件类型。

模式看起来像这样:

private final Map<String, Handler> handlers = new TreeMap<String, Handler>();

public void register(String event, Handler handler) { 
  handlers.put(event, handler); 
}

public void handle(String event) {
  Handler handler = handler.get(event);
  if (handler == null) {
    /* Log or throw an exception for unknown event type. */
  }
  else {
    handler.execute();
  }
}

除了显式注册处理程序之外,您可以使用类似Java 6的ServiceLoader之类的东西,只需将JAR放入类路径中即可添加新行为。

答案 1 :(得分:1)

我会使用Command Pattern的变体。我会扩展Command模式以创建一个IIntervalCommand类。除了Execute方法之外,它还有一个interval属性和一个只读的CanExecute属性。

然后创建一个包含IIntervalCommands列表的CommandList类。它会有一个名为CheckToExecute的方法,你将它传递给当前的游戏时间。 CheckToExecute方法将遍历为每个命令调用CanExecute的列表。如果已经过了经过的时间,CanExecute将返回true。如果CanExecute返回true,则CheckToExecute将调用实现IIntervalCommand的对象的Execute方法。

然后添加其他游戏事件就是创建一个实现IIntervalClass的新类。实例化Object并将其添加到IntervalCommandList。

如果事件的处理非常耗时,那么命令可以将处理作为单独的线程产生。它将返回false到它的CanExecute属性,直到线程返回,即使间隔已经再次通过。或者,如果间隔再次通过,则会产生另一个线程。

你避免了巨大的案例陈述。在实例化对象时,可以消除数据库并设置参数。或者保留它并将其用作创建所有IIntervalCommands的工厂的一部分。

答案 2 :(得分:1)

您可以使用散列表来调度这些事件,而不是打开密钥。这样,您的计时器事件不需要彼此了解。

应该可以做类似的事情:

timerQueue.registerHandler("key",new TimerHandler(){
   // do something timer related  
});

这样,您可以重新启动Java代码处理事件,而不会丢失持久的事件队列。

http://en.wikipedia.org/wiki/Priority_queue'>Priority队列值得关注,如果你还没有。

答案 3 :(得分:0)

我个人不会把它放在数据库中,而是在后台运行一个单独的服务。然后我的web服务或Web应用程序将通过进程间通信与此服务进行通信。不知道这会如何转化为java世界。

答案 4 :(得分:0)

从概念上讲,我认为你做了两件事;

首先,你有一个时间的缩放版本。只要这个时间和挂钟时间之间的关系保持不变,我就可以肯定我只是将这个缩放行为委托给一个类,它会有像

这样的签名。
DateTime getFutureTime( VirtualTimeSpan timespan)

我将使用它将虚拟时间跨度映射到实时实例。此后,您可以实时操作,这可能会稍微简化一些事情,因为您可以使用标准调度功能。

第二部分涉及未来工人流程的调度工作。有许多核心技术可以解决这个问题;从概念上讲,我认为JMS是许多这些的java-grand-dad,它定义的概念很像你正在使用的概念和你需要的概念。我认为看看JMS很适合看到你可能感兴趣的概念,它使用选择器将任务发送给特定的工作人员,就像你描述的那样。

唉,JMS似乎从来没有适合大多数人的账单。很多人发现它太重量级或者实施太多了。所以通常人们最终会采用自制的队列技术。但这些概念都存在。你不能只使用石英吗?