Dois-je prendre soin que le passage dans une représentation de classe d'un fichier de paramètres XML viole la loi de Déméter?

StackOverflow https://stackoverflow.com/questions/3689118

Question

J'utilise un outil pour générer automatiquement une représentation de classe d'un fichier XML hiérarchisé. Le fichier XML est un fichier de paramètres mon besoin d'application pour pouvoir accéder (en lecture seule).

Si je passe dans le nœud de niveau supérieur (par exemple, AppSettings) à une classe qui a besoin d'accéder à un ou plusieurs paramètres, je peux facilement finir avec le code qui ressemble à ceci:

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

Cela semble être une violation grave de la loi de Déméter, mais je me demande si je devrais prendre soin. Je pouvais prendre grand soin de ne laisser passer que dans les paramètres exacts dont j'ai besoin pour chaque classe, mais je vais avoir du mal voyant comment ces multiples points vont me faire du mal dans ce cas.

est le couplage bien mon code à mon format de fichier XML susceptible de créer des problèmes de maintenance ou d'autres problèmes à l'avenir, ou est-ce un exemple où il est logique de ne pas suivre religieusement un principe de conception POO?

Était-ce utile?

La solution

Oui, vous devez prendre soin, pour une raison très pragmatique!

Les classes où vous souhaitez utiliser vos paramètres absolument ne pas besoin de dépendre de la façon dont ces paramètres sont stockés.

Imaginez que dans l'avenir, vous voulez soutenir plusieurs thèmes pour votre application. Vous finirez avec pas un, mais de nombreuses possibilités pour la taille de votre tableau de bord, par exemple:

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

Votre classe d'interface utilisateur a besoin encore qu'une seule chose, une valeur pour sa variable windowSize, il n'a pas besoin de savoir quel thème est actuellement utilisé.

Il est vrai partout où vous disposez d'une interface XML, vous ne voulez pas dépendre du schéma partout dans votre code, mais seulement dans un endroit central.

Par exemple, vous pouvez mettre les paramètres dans une carte à usage interne, comme ceci:

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);
    }
}

Alors vous avez juste un endroit à refactoring pour soutenir un thème, comme celui-ci:

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);
    }
}

Une note finale, juste parce que mon mélange de code pseudo et code java peut dérouter les gens, en particulier les appSettings.Views + theme + Windows.Dashboard.Size: lorsque vous travaillez avec une interface XML, XPath est généralement très utile, même lorsque vous travaillez avec des objets grâce à la bibliothèque belle JXPath (pour java, je ne sais pas pour les autres langues).

Autres conseils

Si vous crachant des données stupides alors il n'y a pas vraiment de meilleure façon de le faire.

je aurais tendance à essayer de travailler vers une solution où l'on pouvait pousser et pop des contextes, cependant.

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

Normalement, les différents Pousse serait dans différentes fonctions ou fichiers, mais sont présentés ici pour titre d'illustration. Peu importe, si vous poussez dans le contexte Vues alors vous venez que si analysez vous êtes à la racine de l'objet.

Si cela est DumbData, cependant, vous pouvez aussi passer juste le genre de chose que « Vues » représente au code qui parse il. haut niveau, votre code ressemblerait à ceci:

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

Ce serait certainement plus « propre » d'un LOD POV, mais il ne peut pas être la peine pour le nombre de paramètres que vous avez. Cependant, avec la profondeur de champ peut-être l'implication est que vous avez beaucoup de paramètres, de sorte que le fractionnement les en zones de responsabilité (pour le chargement et l'enregistrement des paramètres) est probablement sensible.

Toutes les choses sont relatives, cela dépend vraiment de la taille du projet et si vous vous souciez de l'entretien.

Si vous ne se soucient de l'entretien, alors vous ne voulez pas forcer les restrictions imposées par votre source de configuration sur le reste de votre base de code.

La meilleure façon d'y parvenir est de code pour les interfaces et cacher votre implémentation derrière cela. De cette façon, votre code a un contrat avec l'interface de configuration et ne se soucie pas comment la configuration réelle est chargée.

public interface IConfiguration
{
    Size ViewSize { get; }
}

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

Tout le code doit consommer ensuite être codé sur l'interface IConfiguration. Cela signifie que vous pouvez changer la façon dont vous récupérez votre configuration avec un impact minimal.

générations automatiques peuvent être un problème pour les grands projets.

Si vous utilisez le code généré à partir d'un seul endroit (par exemple un seul paquet), peut-être il n'y a pas de problème.

Si vous utiliser du code:

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

dans de nombreux endroits, vous pouvez vouloir cacher une partie de ce couplage faisant une méthode sur l'AppSettings:

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

Mais si vous devez le faire pour toutes les classes, il est peut-être pas viable.

La meilleure décision dépend de la taille de votre projet (et si elle a l'intention de se développer), le temps que vous avez à faire, et la quantité de code généré.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top