我想询问有关如何保持和更改全局应用程序的最佳实践。我有一个Parser(现在是一个单身人士),其中包括像
这样的属性private String mode
private List<String> loadedResources
然后我有大约十个模块,界面非常简单
ModuleOutput parse(String line, Path context) throws ModuleException;
某些模块确实需要(某些模块没有)获取或设置已处理文件的模式。
if (Parser.getInstance().getMode().equals("something") { ... }
或
Parser.getInstance().setMode("something");
它改变了应用程序和解析器本身的状态,其他模块也可以使用它。
两个模块(十个)也想添加到loadedResources
if (!Parser.getInstance().getLoadedResources().contains(resource)) {
Parser.getInstance().getLoadedResources().add(resource);
} else {
// resource already loaded ...
}
但其他人没有。
我不喜欢将全局数据存储在单例中并且有模块到达它(因为测试等)但我甚至不喜欢我需要将所有最终需要的信息发送到可以处理它们的模块。 ..然后创建大对象返回,这将告诉Parser如何更改状态(以及“全局需要”数据可以随时间变化),但它可能会更清洁。你有什么建议?提前谢谢。
答案 0 :(得分:1)
我只想创建一个ParsingContext对象,并将所有可以由模块更改/共享的对象移动到那里。然后我将这个ParsingContext传递给每次调用“ModuleOutput parse”。这意味着ParsingContext将包含解析和资源的状态。通过这种方式,您可以清晰地定义模块共享和更改的内容。请注意,从范围的角度来看,这个ParsingContext的实例对Singleton来说要简洁得多。单身的范围是全局变量。 ParsingContext的范围只是调用“parse”方法和Parser本身。
回答更高层次的问题。我认为没有最佳实践来共享应用程序的全局状态。如果可能的话,目标始终是没有国家。
您可能会问如何在插件和框架之间共享状态。我的观点是你应该使用尽可能最小的对象共享的对象(插件和框架入口点)。 No Singleton,因为通过创建Singleton,您也可以将此状态公开给应用程序的其余部分。
另一个想法是我会尽量减少“耦合”和显式状态。例如,模块的实现包含方法getPriority()。这样,您就可以订购插件了。这迫使开发人员考虑所有可能的模块(甚至是那些他没有实现的模块)并相应地设置优先级。相反,我会采取某种隐式排序。例如,通过创建解析器的几个明确定义的阶段,并要求开发人员将模块“绑定”到此阶段。通过这样做,开发人员只考虑少量的预定义解析器阶段,而不是模块的任意排序。
另外,考虑到实现,我会考虑为模块实现Parser类和Chain of Responsibility模式的State设计模式。然而,很难说它是否可以实现,我将不得不深入研究源代码并编写一些单元测试来测试解析功能。