我正处于大规模重构项目的中间,代码有一个5000行主类,它被注入所有内容,存储所有内容并拥有所有常用代码。
我不是分析和设计方面的专家,但是我已经尽我所能地分离出了一些东西,而我通过重构依赖于主要类的类来重构大约80%我创建的新课程。
有些类型的数据在应用程序启动时初始化,并且在应用程序的整个生命周期中几乎所有内容都可以访问。例如,有一个Config类,它包含数百个参数。
我采用的方法是创建几个单例,其中最核心的是GUIData和ClientData。 GUIData包含对应用程序主机的引用,clientdata维护对配置和其他类似类的引用。
这允许我从代码中的任何地方调用ClientData.getInstance()。getConfig()。getParam(" param")但我不觉得这是最好的方法。
我考虑过单独的静态类而不是包含类实例的这些数据单例,但是有些类确实需要构造函数。
我一直在谷歌搜索和关闭一个星期试图找到一个更好的方法来做到这一点但不知何故我总是最终谈论数据库缓存的线程
答案 0 :(得分:2)
不可变(配置)实例提供"线程安全的应用程序范围的数据访问"。 Typesafe的config(正如Brian Kent的评论中所建议的那样)正是如此。 请注意,这不涉及静态类或单例。静态课程和单身人士现在可以满足您的需求, 但是他们将来可能会很麻烦。它们可以很方便,但试着限制它们的使用。
必须在读取和解析配置数据后进行初始化。它通常在应用程序启动时完成,然后启动其他处理线程。初始化必须尽可能多地验证配置数据,以便快速失败并在配置数据不佳时终止程序。
将大量配置数据捆绑在一起可以创建隐藏的通信线路"。例如。您更新一个值并且应用程序失败,因为它还需要更新其他值。将所有配置数据放在一个文件中并从那里加载它是完美的,但是您的应用程序(具有数百个配置选项)应该将应用程序的不同部分使用的组中的配置数据分开。这可以改善隔离,帮助进行单元测试,并且可以在将来更改应用程序,而不会产生太多令人讨厌的意外。
有两种方法可以使用一组配置数据:
Settings.getInstance().getConfigForThisModule()
。 setConfig(ConfigForThisModule config)
为每个使用配置数据的对象提供配置数据。第一种方法取决于不召唤Settings.getInstance().getConfigForACompletelyUnrelatedModule()
的惯例,这可能是一个弱点。第二种方法更符合"依赖注入"并且可能是未来的证据。
您可以在重构时混合使用这两种方法,只需确保一致(例如,仅对应用程序的所有部分中使用的配置数据使用单例方法)。
要进一步改进使用配置数据的设计,请记住以下(可能)未来的功能要求:更新配置文件时,将重新加载配置数据并在应用程序中使用。大多数日志记录框架都设法支持此功能需求,而不会影响多线程应用程序的性能。除此之外,还需要以下应用程序:
ConfigForThisModule
实例的引用,而应调用Settings.getInstance()...
(或其他可返回更新实例的方法) regurarly。AtomicReference
返回的新配置实例更新Settings.getInstance()...
一样简单。但这也是测试配置数据集隔离的地方:使用一个模块中的旧集合和另一个模块中的新集合应该没有问题。配置数据可以看作是一种全球状态"。考虑到这一点,在以下两个问题中讨论了关于做什么和避免什么(部分公然复制到这个答案)的进一步设计要点:
答案 1 :(得分:0)
很抱歉,问题有点模糊,您是否希望存储配置或程序其他部分使用的缓存对象?
由于您有100多个参数,所以首先将配置拆分为可管理的块
1)将配置参数拆分为与简单属性文件1:1对应的逻辑块 - 需要一些时间
2)这些属性文件必须外部化,以便您可以在任何时间点更改它们,确保通过env变量将基本位置传递给程序
3)编写一个包含Apache commons configuration的实用程序类(单例)来保存您的配置。 (从基本位置读取* .properties并将属性合并到一个配置对象中)这必须在任何线程启动之前完成。
4)使用config.getXXXX()方法
参考代码中的配置参数Apache commons config还能够在文件系统上更改属性文件时重新加载配置。
完成此操作后,使用像Spring或Guice这样的DI容器来缓存已配置的对象。
答案 2 :(得分:0)
如果它只是您需要的字符串属性值,那么您甚至不需要一个类 - 已经存在一个全局工具:System.getProperties()
您需要做的就是首先在启动时加载属性值:
System.setProperty("myKey", "myValue"); // see below how load properties from a file
然后在代码中的任何地方阅读:
String myValue = System.getProperty("myKey");
或
String myValue = System.getProperty("myKey", "my desired default");
如果您的容器不支持开箱即用的属性加载,则从外部文件加载属性,如下所示:
key1=value
key2=some other value
etc...
您可以使用此代码:
Files.lines(Paths.get("path/to/file"))
.filter(line -> !line.startsWith("#") || !line.contains("=")) // ignore comment/blank
.map(line -> line.split("=", 2)) // split into key/value
.forEach(split -> System.setProperty(split[0], split[1])); // load as property
答案 3 :(得分:0)
你可以使用Java Properties类util,基本上它是一个HashTable 参考:https://docs.oracle.com/javase/7/docs/api/java/util/Properties.html
创建文件fileName.properties并将数据存储在键值对中,例如:
username=your name
port=8080
然后将其加载到Properties Object中并获取如下数据:
Properties prop = new Properties();
load the file...
String userName = prop.getProperty("username")
String port = prop.getProperty("port")// you can parse it to int if needed
我建议为每种类型的配置创建一个属性文件,如:
你可以按照这个简单的教程 http://www.mkyong.com/java/java-properties-file-examples/