我正处于一个大规模重构项目的中间,代码有一个5000行主类,它被注入到所有内容中,存储了所有内容并拥有所有常用代码.
我不是分析和设计方面的专家,但是我已经尽可能地分离了一些东西,并且通过重构依赖于主类的类来使用我创建的新类,我大约80%.
有些类型的数据在应用程序启动时初始化,并且在应用程序的整个生命周期中都可以访问.例如,有一个Config类,它包含数百个参数.
我采用的方法是创建几个单例,其中最重要的两个是GUIData和ClientData. GUIData包含对应用程序主机的引用,clientdata维护对配置和其他类似类的引用.
这允许我从代码中的任何地方调用ClientData.getInstance().getConfig().getParam(“param”),但我不认为这是最好的方法.
我考虑了单个静态类而不是包含类实例的这些数据单例,但是一些类确实需要构造函数.
我一直在谷歌搜索和关闭一个星期试图找到一个更好的方法来做到这一点,但不知怎的,我总是最终在谈论数据库缓存的线程
最佳答案 不可变(配置)实例提供“线程安全的应用程序范围的数据访问”.
Typesafe的
config(正如Brian Kent的评论中所建议的那样)正是如此.
请注意,这不涉及静态类或单例.静态课程和单身人士现在可以满足您的需求,
但是他们将来可能会很麻烦.它们可以很方便,但尝试限制它们的使用.
在读取和解析配置数据之后,必须进行初始化.它通常在应用程序启动时完成,然后启动其他处理线程.初始化必须尽可能多地验证配置数据,以便快速失败并在配置数据不佳时终止程序.
将大量配置数据捆绑在一起可以创建“隐藏的通信线”.例如.您更新一个值并且应用程序失败,因为它还需要更新其他值.将所有配置数据放在一个文件中并从那里加载它是完美的,但是您的应用程序(具有数百个配置选项)应该将应用程序的不同部分使用的组中的配置数据分开.这可以改善隔离,帮助进行单元测试,并且可以在将来更改应用程序,而不会产生太多令人讨厌的意外.
有两种方法可以使用一组配置数据:
>从对象内部调用单例Settings.getInstance().getConfigForThisModule().
>通过构造函数或通过setConfig(ConfigForThisModule config)为每个使用配置数据的对象提供配置数据.
第一种方法取决于不调用Settings.getInstance().getConfigForACompletelyUnrelatedModule()的约定,这可能是一个弱点.第二种方法更符合“依赖注入”,可能更具未来性.
您可以在重构时混合使用这两种方法,只需确保一致(例如,仅对应用程序的所有部分中使用的配置数据使用单例方法).
为了进一步改进使用配置数据的设计,请记住以下(可能)未来的功能要求:更新配置文件时,将重新加载配置数据并在应用程序中使用.大多数日志记录框架都设法支持此功能需求,而不会影响多线程应用程序的性能.除其他外,它需要以下您的应用程序:
>如果新配置数据不好,程序不会终止,而是记录错误,旧配置数据仍在使用中.您的初始化过程将需要处理“重新加载时加载”和“重新加载”方案.要消除这一点的主要原因是您的初始化过程需要可重用,并且不应影响应用程序的其他(运行)部分(再次隔离).
>长期存在的对象可能不会保留配置数据的本地副本或对ConfigForThisModule实例的引用,而是应该重新调用Settings.getInstance()…(或其他可以返回更新实例的方法).
>用新配置替换旧配置可能不会导致错误.从技术上讲,替换配置就像使用Settings.getInstance()返回的新配置实例更新AtomicReference一样简单….但这也是测试配置数据集隔离的地方:使用一个应该没有问题旧的设置在一个模块中,另一个模块中的新设置在同一个模块中.
配置数据可以看作是一种“全局状态”.考虑到这一点,在以下两个问题中讨论了关于做什么和避免什么(部分公然复制到这个答案)的进一步设计要点: