“主人偏好”课是一个好主意吗?

时间:2009-02-26 23:34:36

标签: java design-patterns

我有一个管理大型软件项目的用户首选项的类。项目中可能需要从持久性存储设置或检索用户首选项的任何类都是在此类上调用静态方法。这种集中管理允许以编程方式完全删除首选项 - 如果每个首选项都在其使用代码附近处理,则无法在整个项目中进行处理。

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

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

但是现在pref经理已成为一个“章鱼类”,将各种类型的类吸入到不应该存在的API jar中。如果没有,那么使用API​​ jar的程序很快会遇到ClassDef异常。如果确实如此,则API jar现在变得臃肿,因为其他每个类都可能引用其他类。

通常,其他Java程序员是否使用集中式类来管理他们的首选项?

将静态pref管理类作为公共API的一部分进行分发是否有意义?

该pref经理是否应该成为确定默认值的代码的守护者?

6 个答案:

答案 0 :(得分:11)

恕我直言,我认为你的第一个问题的答案是“是”和“否”。

首选项通常作为集中式类处理,因为类是项目中许多类的“接收器”。尝试更接近调用代码意味着如果相同的首选项稍后在其他地方有用,则会遇到麻烦。根据我的经验,尝试将偏好设置得“太近”也会导致处理方式非常不一致。

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

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

对于您的其他问题,我会说您的公共API应该有一种让用户更改首选项的方法,但前提是您可以很好地记录这些更改的结果。

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

答案 1 :(得分:4)

难道你不能以一种非常通用的方式处理偏好吗?然后,您只需使用首选项管理器来处理持久性。所以从一个类你只需要说一下偏好管理器PreferenceManager.setPreference(key,value),它就不关心它在数据语义方面的保存。

或者我是否过分简化了这一点?

答案 2 :(得分:2)

我不是Java Dev,但就整个“章鱼类”而言,你能不能只为jar提供一个接口,并在运行时连接接口和prefs管理器之间的调用,使用应用程序配置文件确定要实例化的prefs管理器?

类似于.NET提供程序模式吗?

这样你就可以将你的jar与prefs管理器分离。

答案 3 :(得分:1)

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

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

因此,在您的情况下,您可以为类提供一种方法,以便在访问(可能)用户定义的值之前为其设置默认值。首选项类不必了解它所服务的类。

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

答案 4 :(得分:0)

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

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

您是否可以通过为该区域的模式后面的每个区域使用首选项容器类来满足这两个要求,但是让它注册“全局”首选项对象集合?

您的全局集合可以执行诸如迭代每组首选项并将其重置为默认值的操作,但您的首选项本身仍将在本地定义和维护,以便它不会分散到代码的其他部分。

我能看到的唯一问题是,如果你允许首选项对象在实例化时注册自己,你就有可能尝试“重置为默认值”而某些首选项尚未实例化。

我认为这可以通过让主“首选”类实例化所有其他类来解决,然后任何一段代码都可以通过静态getter从中央首选项中检索它的本地首选项对象。

这似乎与一些记录器的工作原理非常相似。有一个维护日志级别,输出流等的中央机制,但每个类都有自己的“log”方法实例并记录到它。

我希望这更符合目标。哦,我也同意接受的答案,不要让你的所有方法都是静态的,总是使用吸气剂 - 你很高兴有一天能做到。

答案 5 :(得分:0)

JSR-10(java.util.prefs.*)API使用带Class<?>参数的工厂方法来创建Preferences个实例。这样,API可以将属于同一个包的不同类的首选项存储在一个文件中。