代码之家  ›  专栏  ›  技术社区  ›  devuxer

我应该注意传递XML设置文件的类表示形式是否违反了德米特定律?

  •  4
  • devuxer  · 技术社区  · 14 年前

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

    如果我通过顶层节点(例如, AppSettings )对于需要访问一个或多个设置的类,我可以很容易地得到如下所示的代码:

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

    这似乎严重违反了德米特的法律,但我想知道我是否应该关心。我可能会花很大的努力来通过每门课我需要的精确设置,但在这种情况下,我很难看到这些多点会如何伤害我。

    是否将代码与XML文件格式紧密耦合,可能会在将来造成维护问题或其他问题,或者这是一个不认真遵循OOP设计原则的示例?

    4 回复  |  直到 14 年前
        1
  •  6
  •   Damien    14 年前

    是的,你应该关心,因为一个非常务实的理由!

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

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

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

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

    无论您在哪里有一个XML接口,您都不希望依赖于代码中的任何地方的模式,而是只在一个中心位置。

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

    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通常非常有用,即使使用对象时,也要感谢nice库。 JXPath (对于Java,我不知道其他语言)。

        2
  •  1
  •   dash-tom-bang    14 年前

    如果你吐出的是愚蠢的数据,那么就没有更好的方法了。

    不过,我倾向于尝试一种解决方案,在这个方案中你可以推动和弹出上下文。

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

    通常,不同的推送会出现在不同的函数或文件中,但为了便于说明,这里显示了这些推送。不管怎样,如果将其推到视图上下文中,那么只需像解析对象的根一样对其进行解析。

    如果这是dumbdata,那么您也可以将“views”表示的类型传递给解析它的代码。顶级,您的代码如下所示:

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

    这当然是从一个lod pov“清洁”,但它可能不值得为您的设置数量。但是,使用范围深度可能意味着您有很多设置,因此将它们划分为责任区域(用于加载和保存设置)可能是明智的。

        3
  •  1
  •   Bronumski    14 年前

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

    如果您确实关心维护,那么您不想强制配置源对其余代码基施加任何限制。

    实现这一点的最佳方法是编码到接口,并将实现隐藏在接口后面。这样,您的代码就与您的配置接口有了约定,而不关心实际的配置是如何加载的。

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

    然后,应根据IConfiguration接口对所有消费代码进行编码。这意味着您可以以最小的影响更改检索配置的方式。

        4
  •  0
  •   Student    14 年前

    自动生成可能是大型项目的一个问题。

    如果您将使用从单个位置(例如单个包)生成的代码,那么可能没有问题。

    如果您要使用代码:

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

    在许多地方,您可能希望隐藏一些这样的耦合,在 AppSettings :

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

    但是如果你需要对所有的课程都这样做,也许这是不可行的。

    最佳决策取决于项目的大小(如果它打算增长的话)、您必须做的时间以及生成的代码的数量。