27 votes

Modèle de conception pouvant remplacer l'interrupteur / goto chaîné?

J'ai un code pour mettre à jour mes ressources d'application vers la version actuelle de l'application. Ce code est appelé après la mise à jour de l'application.

 int version = 1002;   // current app version

switch(version)
{
   case 1001:
      updateTo1002();
      goto case 1002;

   case 1002:
      updateTo1003();
      goto case 1003;

   case 1003:
      updateTo1004();
      goto case 1004;
      break;

   case 1004:
      updateTo1005();
      break;
}
 

Ici, nous avons une méthode en cascade appelant en sautant au bloc de cas spécifié. Je me demande - est-ce une bonne pratique à utiliser (souvent considérée comme une mauvaise pratique!) Dans ce cas? Je ne veux pas appeler la méthode l'une après l'autre - comme ceci:

 updateTo1002()
{
   // do the job
   updateTo1003();
}
updateTo1003()
{
   // do the job
   updateTo1004();
}
 

Y a-t-il un modèle de conception qui décrit un tel problème?

38voto

JaredPar Points 333733

Dans l'exemple, la version augmente et appelle toujours les précédentes en séquence. Je pense qu'un ensemble de déclarations if est probablement plus approprié ici

 if (version == 1001 ) { 
  updateTo1002();
}

if (version <= 1002) {
  updateTo1003();
}

if (version <= 1003) {
  updateTo1004(); 
}

if (version <= 1004) {
  updateTo1005();
}
 

Certains ont fait remarquer que cette approche est irréalisable car le nombre de versions augmente (pensez à environ 50). Dans ce cas, voici une version plus facile à maintenir

 private List<Tuple<int, Action>> m_upgradeList;

public Program()
{
    m_upgradeList = new List<Tuple<int, Action>> {
        Tuple.Create(1001, new Action(updateTo1002)),
        Tuple.Create(1002, new Action(updateTo1003)),
        Tuple.Create(1003, new Action(updateTo1004)),
        Tuple.Create(1004, new Action(updateTo1005)),
    };
}

public void Upgrade(int version)
{
    foreach (var tuple in m_upgradeList)
    {
        if (version <= tuple.Item1)
        {
            tuple.Item2();
        }
    }
}
 

6voto

Andrew Bezzub Points 8794

goto est toujours considéré comme une mauvaise pratique. Si vous utiliser goto, il est généralement plus difficile de lire le code et vous pouvez toujours écrire votre code différemment.

Par exemple, vous pouvez utiliser lié liste pour créer une chaîne de méthodes et de certains processeurs de classe que les processus de la chaîne. (Voir pst de répondre pour de bon exemple.). Il est beaucoup plus orienté objet et maintenable. Ou si vous devez en ajouter un appel de méthode entre 1003 des cas et d' 1004?

Et bien sûr voir cette question.

alt text

6voto

Dave White Points 2896

Je déteste le vide des déclarations qui ne fournissent pas de renseignements à l'appui, mais goto est assez universellement décrié (et pour cause) et il y a de meilleures façons d'atteindre les mêmes résultats. Vous pouvez essayer de la Chaîne de Responsabilité motif qui permettront d'atteindre les mêmes résultats, sans les "spaghetti-ish" goo un goto mise en œuvre peut se transformer en.

La chaîne de Responsabilité motif.

2voto

dahlbyk Points 24897

Je suggérerais une variation du modèle de commande, chaque commande étant auto-validée:

 interface IUpgradeCommand<TApp>()
{
    bool UpgradeApplies(TApp app);
    void ApplyUpgrade(TApp app);
}

class UpgradeTo1002 : IUpgradeCommand<App>
{
    bool UpgradeApplies(App app) { return app.Version < 1002; }

    void ApplyUpgrade(App app) {
        // ...
        app.Version = 1002;
    }
}

class App
{
    public int Version { get; set; }

    IUpgradeCommand<App>[] upgrades = new[] {
        new UpgradeTo1001(),
        new UpgradeTo1002(),
        new UpgradeTo1003(),
    }

    void Upgrade()
    {
        foreach(var u in upgrades)
            if(u.UpgradeApplies(this))
                u.ApplyUpgrade(this);
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X