Java 更改和发送全球需要的数据

Java 更改和发送全球需要的数据,java,architecture,singleton,global-state,Java,Architecture,Singleton,Global State,我想问一下如何保持和更改应用程序的全局状态的最佳实践。我有一个解析器(现在是一个单例解析器),它的属性包括 private String mode private List<String> loadedResources 有些模块确实需要(有些模块不需要)获取或设置已处理文件的模式 if (Parser.getInstance().getMode().equals("something") { ... } 或 这会改变应用程序和解析器本身的状态,其他模块也会使用它 两个模块(共十

我想问一下如何保持和更改应用程序的全局状态的最佳实践。我有一个解析器(现在是一个单例解析器),它的属性包括

private String mode
private List<String> loadedResources
有些模块确实需要(有些模块不需要)获取或设置已处理文件的模式

if (Parser.getInstance().getMode().equals("something") { ... }

这会改变应用程序和解析器本身的状态,其他模块也会使用它

两个模块(共十个)也要添加到loadedResources

if (!Parser.getInstance().getLoadedResources().contains(resource)) {
     Parser.getInstance().getLoadedResources().add(resource);
} else {
     // resource already loaded ...
}
但其他人则不然


我不喜欢将全局数据存储在singleton中,并让模块访问它(因为测试等),但我甚至不喜欢我需要将最终需要的所有信息发送给能够处理它们的模块。。。然后创建要返回的大对象,这将告诉解析器如何更改状态(以及“全局需要的”数据可能会随着时间的推移而改变),但是这可能会更干净。你有什么建议?提前感谢。

我只需要创建一个ParsingContext对象,并将模块可以更改/共享的所有内容移到那里。然后我将把这个ParsingContext传递到“ModuleOutput parse”的每个调用中。这意味着ParsingContext将包含解析和资源的状态。通过这种方式,您可以清晰地定义模块可以共享和更改的内容。请注意,从范围的角度来看,这个ParsingContext的实例比Singleton要干净得多。singleton的范围是全局变量。ParsingContext的作用域仅是“parse”方法和解析器本身的调用

回答更高层次的问题。我认为并没有最佳实践来共享应用程序的全局状态。如果可能的话,目标总是没有状态

您可能会问如何在插件和框架之间共享状态。我的意见是,您应该使用由尽可能少的对象(插件和框架入口点)共享的对象。没有单例,因为通过创建单例,您也可以将此状态公开给应用程序的其余部分

另一个想法是,我将最小化“耦合”和显式状态。例如,模块的实现包含方法getPriority()。这样,您就可以订购插件了。这迫使开发人员考虑所有可能的模块(甚至那些他没有实现的模块)并相应地设置优先级。相反,我会选择某种隐式排序。例如,创建几个定义良好的解析器阶段,并要求开发人员将模块“绑定”到此阶段。通过这样做,开发人员只考虑少量预定义的解析器阶段,而不是模块的任意顺序


此外,考虑到实现,我将考虑为模块的解析器类和责任链模式实现状态设计模式。然而,很难说它是否可以实现,我必须深入挖掘源代码并编写一些单元测试来测试解析功能。

为什么您的解析器需要是一个单独的解析器?为什么每个模块不能有自己的解析器?Singleton是一种设计风格,可变的Singleton更是如此。因为这是另一种方式->只有一个解析器调用其模块(模块作为服务加载,因此用户可以创建自己的模块解析文件的每一行)
Parser.getInstance().setMode("something");
if (!Parser.getInstance().getLoadedResources().contains(resource)) {
     Parser.getInstance().getLoadedResources().add(resource);
} else {
     // resource already loaded ...
}