Java 是一个;“主首选项”;上课好主意?

Java 是一个;“主首选项”;上课好主意?,java,design-patterns,Java,Design Patterns,我有一个类,用于管理大型软件项目的用户首选项。项目中可能需要从持久性存储设置或检索用户首选项的任何类都将调用该类上的静态方法。这种集中化管理允许以编程方式完全删除首选项—如果每个pref的处理都接近其使用代码(散布在整个项目中),这将是不可能的 在此过程中,我遇到了集中化设计的另一个含义。该软件有一个公共API。该API可以在jar中自行提供。该API中的类可能引用pref管理类。因此,pref管理器必须放在API jar中 每个首选项可能都有一个默认值。软件启动时,可能会计算默认值。算法取决于

我有一个类,用于管理大型软件项目的用户首选项。项目中可能需要从持久性存储设置或检索用户首选项的任何类都将调用该类上的静态方法。这种集中化管理允许以编程方式完全删除首选项—如果每个pref的处理都接近其使用代码(散布在整个项目中),这将是不可能的

在此过程中,我遇到了集中化设计的另一个含义。该软件有一个公共API。该API可以在jar中自行提供。该API中的类可能引用pref管理类。因此,pref管理器必须放在API jar中

每个首选项可能都有一个默认值。软件启动时,可能会计算默认值。算法取决于偏好,因此倾向于驻留在使用代码附近。因此,如果pref管理器需要提供一个默认值,它将调用有问题的类

但是现在pref管理器已经变成了一个“八达通类”,将各种不应该存在的类吸入API jar中。如果没有,那么使用API jar的程序很快就会遇到ClassDef异常。如果是这样,那么API jar现在就膨胀了,因为其他每个类都可能引用其他类

一般来说,其他Java程序员是否使用集中的类来管理他们的首选项

将静态pref管理类作为公共API的一部分分发有意义吗


pref经理应该是确定默认值代码的保管人吗?

IMHO,我认为您的第一个问题的答案是“是”和“否”

首选项通常作为一个集中的类处理,因为该类是项目中许多类的“接收器”。尝试在更接近调用代码的地方执行此操作意味着,如果相同的首选项稍后在其他地方有用,那么您就有麻烦了。根据我的经验,试图将首选项“放得太近”也会导致非常不一致的处理

也就是说,通常最好使用多个偏好类或“偏好集”,每个偏好类或“偏好集”支持一个模块或子模块。如果您查看体系结构的主要组件,通常会发现首选项集可以进行逻辑分区。这减少了每个首选项类中的混乱。更重要的是,它将允许您在将来将程序拆分为多个JAR。现在,“默认值”计算器可以放在模块中,但仍然可以放在一个足够全局的区域中

我还建议不要直接将首选项设置为静态方法,而是使用一些类似getInstance()的操作来获取preferences manage的共享实例,然后对其进行操作。根据您的语义,您可能希望锁定该对象一段时间(例如,当用户在UI中编辑首选项时),如果您有一个实际的对象,这会更容易

对于您的其他问题,我认为您的公共API应该有一种允许用户更改首选项的方法,但前提是您能够充分记录这些更改的结果


如果您使用单个API函数来获取“参考管理器”,则可以为用户提供自己的“默认值计算器”。首选项管理器会先询问这个计算器,然后再使用默认情况下您提供的计算器。

您不能用真正通用的方式处理首选项吗?然后,您只需使用首选项管理器来处理持久性。因此,从一个类中,您只需要对preference manager PreferenceManager.setPreference(key,value)说,它并不关心它在数据语义方面保存了什么


还是我把这个简化得太多了?

你可能想看看Cocoa的
NSUserDefaults
课程,从中获得灵感。它通过具有多层首选项(称为域)来处理您描述的问题。当您查找键的值时,例如“PrintUsingAllCaps”,它首先检查用户本地域中的值。如果在那里找不到,它可以检查系统范围的域或网络级别的域,依此类推

它最后检查的绝对位置称为“注册域”,这基本上是硬编码默认值应该去的地方。因此,在我的代码中的任何时候,我都可以在注册域中写入一个首选项,
NSUserDefaults
仅在用户没有覆盖它的情况下才提供该值

因此,在您的例子中,您可以为类提供一种方法,以便在键访问(可能)用户定义的值之前为其设置默认值。preferences类不必知道它所服务的类的任何信息


正如其他人所建议的,如果您需要更复杂的东西,您可以设置一个
DefaultValueProvider
回调对象,而不是直接的值。

我不是Java开发人员,但就整个“octopus类”而言,您是否可以在运行时使用应用程序配置文件确定要实例化的prefs管理器,为jar提供一个接口并连接接口和prefs管理器之间的调用

类似于.NET提供程序模式的东西


这样,您就可以将jar与prefs manager分离。

我删除了我的第一个答案,因为我误解了作者的要求

要真正解决实际问题——感觉您希望将首选项(以及默认值的计算)与使用它们的代码放在一起是有意义的

通过为每个遵循该区域模式的区域使用preferences容器类,但将其注册到“全局”首选项对象集合,您能满足这两个要求吗

您的全局集合可以做一些事情,比如迭代每一组首选项并将其重置为默认值,但您的首选项本身仍然可以