4

我正在使用一种工具来自动生成分层组织的 XML 文件的类表示。XML 文件是我的应用程序需要能够访问的设置文件(只读)。

如果我将顶级节点(例如,AppSettings)传递给需要访问一个或多个设置的类,我很容易得到如下所示的代码:

var windowSize = AppSettings.Views.Windows.Dashboard.Size;

这似乎严重违反了得墨忒耳法则,但我想知道我是否应该在意。我可以不遗余力地只传递每节课所需的确切设置,但是在这种情况下,我无法看到这些多个点将如何伤害我。

将我的代码与我的 XML 文件格式紧密耦合是否可能会在未来产生维护问题或其他问题,或者这是一个不虔诚地遵循 OOP 设计原则有意义的示例?

4

4 回答 4

6

是的,出于非常务实的原因,您应该关心!

您要使用设置的类绝对不需要依赖于这些设置的存储方式。

想象一下,将来您希望为您的应用程序支持多个主题。您的仪表板大小最终将不是一种,而是多种可能性,例如:

AppSettings.Views.ThemeA.Windows.Dashboard.Size;
AppSettings.Views.ThemeB.Windows.Dashboard.Size;

你的 UI 类仍然只需要一件事,它的变量 windowSize 的值,它不需要知道当前使用的是哪个主题。

确实,只要您有一个 XML 接口,您就不想在代码中的任何地方都依赖于模式,而只依赖于一个中心位置。

例如,您可以将设置放在内部使用的 Map 中,如下所示:

public class SettingsReader {

    public static final String VIEW_WINDOW_DASHBOARD_SIZE = "Views.Windows.Dashboard.Size";

    private Map settings = new Hashmap();

    public SettingsReader(AppSettings appSettings) {
        settings.put(VIEW_WINDOW_DASHBOARD_SIZE, appSettings.Views.Windows.Dashboard.Size);
    }

    public String getSettingValue(String key) {
        return settings.get(key);
    }
}

然后你只有一个地方可以重构来支持一个主题,就像这样:

public class SettingsReader {

    public static final String VIEW_WINDOW_DASHBOARD_SIZE = "Views.Windows.Dashboard.Size";

    private Map settings = new Hashmap();

    public SettingsReader(AppSettings appSettings, String theme) {
        settings.put(VIEW_WINDOW_DASHBOARD_SIZE, appSettings.Views + theme + Windows.Dashboard.Size);
    }

    public String getSettingValue(String key) {
        return settings.get(key);
    }
}

最后一点,只是因为我的伪代码和 java 代码的混合可能会让人感到困惑,尤其是appSettings.Views + theme + Windows.Dashboard.Size: 当使用 XML 接口时,xPath 通常非常有用,即使在使用对象时也非常有用,这要归功于漂亮的库JXPath(对于 java,我不知道其他语言)。

于 2010-09-14T21:47:45.593 回答
1

如果您正在吐出愚蠢的数据,那么实际上没有更好的方法可以做到这一点。

不过,我倾向于尝试找到一个可以推送和弹出上下文的解决方案。

PushContext(AppSettings)
  // do child contexts
  PushContext(Views)
    // more child contexts
    PushContext(Windows)
    // etc.
    PopContext()
  PopContext()
PopContext()

通常不同的推送会在不同的函数或文件中,但为了说明起见,这里显示。无论如何,如果您推入 Views 上下文,那么您只需解析它,就好像您在对象的根目录中一样。

但是,如果这是 DumbData,您也可以将“视图”表示的事物类型传递给解析它的代码。顶级,您的代码如下所示:

views.ParseSettings(AppSettings.Views);
locale.ParseSettings(AppSettings.Locale);
network.ParseSettings(AppSettings.Network);

从 LOD POV 来看,这肯定会“更干净”,但对于您拥有的设置数量而言,这可能不值得。但是,使用范围深度可能意味着您有很多设置,因此将它们分成责任区域(用于加载和保存设置)可能是明智的。

于 2010-09-10T23:56:48.490 回答
1

所有事情都是相对的,这实际上取决于项目的大小以及您是否关心维护。

如果您确实关心维护,那么您不希望将配置源施加的任何限制强加于您的代码库的其余部分。

实现这一点的最佳方法是对接口进行编码并将您的实现隐藏在其后面。这样你的代码与你的配置接口有一个契约,而不关心实际配置是如何加载的。

public interface IConfiguration
{
    Size ViewSize { get; }
}

public class AppSettingsConfiguration : IConfiguration
{
     public Size ViewSize
     {
          return AppSettings.Views.Windows.Dashboard.Size;
     }
}

然后应针对 IConfiguration 接口对所有使用代码进行编码。这意味着您可以在影响最小的情况下更改检索配置的方式。

于 2010-09-16T22:47:17.087 回答
0

对于大型项目来说,自动生成可能是个问题。

如果您将使用从一个地方(例如单个包)生成的代码,也许没有问题。

如果您将使用代码:

var windowSize = AppSettings.Views.Windows.Dashboard.Size;

在许多地方,您可能希望隐藏一些这种耦合,从而在以下位置创建一个方法AppSettings

getSize() {
  return Views.Windows.Dashboard.Size;
}

但是,如果您需要对所有班级都这样做,那可能是不可行的。

最好的决定取决于你的项目的大小(如果它打算扩大),你必须做的时间,以及生成的代码量。

于 2010-09-14T12:47:12.773 回答