2016-06-08 1 views
2

Je suis en train d'écrire du code en C# et j'ai remarqué un scénario comme ci-dessous. Je me demande comment je peux rendre cela plus élégant et facile à entretenir.Méthode surchargée ou quelque chose de plus élégant?

Si je suivant le scénario avec

surcharge
public void DoSmtg(string a) { DoSmtg(a, 0, 0f); } 
public void DoSmtg(string a, int x) { DoSmtg(a, x, 0f); } 
public void DoSmtg(string a, int x, double d) { // method logic } 

dire maintenant, je dois ajouter un autre paramètre bool. Je devrais modifier cela à

Ceci est un exemple très simple. Il est possible d'avoir 10 autres versions de la méthode DoSmtg(). Clairement, ce code sent. Alors que la saturation est tout à fait valable, il est évidemment difficile de maintenir ce code depuis:

  1. il existe de nombreuses méthodes à écrire

  2. il est évident que la méthode est appelée jusqu'à une enquête minutieuse (surtout si méthode a plus de paramètres)

  3. méthode

    se poluted par la croissance liste des paramètres

  4. le nouveau paramètre ajouté nécessite des changements à de nombreux endroits (pensez à la métho ds ci-dessus appelé à partir de nombreux endroits différents)

Ce qui serait un moyen élégant, simple et bon d'éviter quelque chose comme ça?

+5

Si ces paramètres sont liés de quelque façon que ce soit, envisagez de les regrouper dans une classe et de faire de '.DoSmtg' une méthode de cette classe. –

+1

Ce que @JeroenMostert a dit; Je tapais juste le même commentaire. :) Ou même si 'DoSmtg' n'est pas un membre de la classe, peut-être que les formals sont des données de configuration associées; alors il pourrait être utile de faire une abstraction spécifique à ce concept et de le passer à 'DoSmtg'. (Bien sûr, cela ne fait que déplacer le problème, maintenant vous avez le même problème pour les constructeurs de l'abstraction.) –

+1

https://en.wikipedia.org/wiki/Builder_pattern – sstan

Répondre

3

Vous pouvez essayer d'ajouter tous les paramètres sur une fonction, en utilisant les valeurs par défaut et nommez les paramètres lorsque vous appelez la fonction:

public void DoSmtg(string a, int x=0, double d=0f, bool doIt=false) { 
    // method logic 
} 

Lorsque vous appelez la fonction, alors vous feriez:

DoSmtg("yo!") 
DoSmtg("yo!", d:0.59, doIt:true) 
+0

Gardez à l'esprit que cela casse le code compilé existant qui dépend des autres surcharges. –

+1

Bon point. Il y a aussi des ruptures possibles lors de la recompilation du code. Un exemple: dans le code original, 'Action a = DoSmtg;' est légal; dans le nouveau code ce n'est pas le cas et cela deviendrait une erreur. –

+1

Visual Studio a un excellent support de refactoring;) –

3

Vous pouvez envelopper tous les paramètres dans un POCO:

public class SomethingParameters 
{ 
    public string A { get; set; } 
    public int X { get; set; } 
    public double D { get; set; } 
    public bool DoIt { get; set; } 
} 

Ensuite, la méthode la signature devient:

public void DoSmtg(SomethingParameters parameters) { // method logic } 

J'aime ce motif car il est facile de le prolonger dans le futur. Si vous avez besoin d'ajouter cinq paramètres supplémentaires, ou des paramètres optionnels, pas de problème!

Vous pouvez l'appeler comme:

var parameters = new SomethingParameters() 
{ 
    A = "foobar", 
    X = 123, 
    D = 0.123, 
    DoIt = false 
} 

DoSmtg(parameters); 

Si vous avez beaucoup de code appelant l'ancienne signature de la méthode que vous ne voulez pas casser, vous pouvez garder vos surcharges existantes, mais ne les appeler la nouvelle un:

public void DoSmtg(string a, int x, double d, bool doIt) 
    => DoSmtg(new SomethingParameters() 
       { 
        A = a, 
        X = x, 
        D = d, 
        DoIt = doIt 
       }); 
+0

J'aime votre idée mais je ne suis pas sûr de savoir comment invoquer la méthode. Je dois instancier l'instance de la classe sur chaque appel et définir ses paramètres à droite? Quelque chose comme DoSmtg (new SomethingParameters (A, X, D, DoIt)). J'aime ça mais il y a un problème avec les paramètres publics et ça semble être toujours le même problème. Bien que plus élégant. – pixel

+0

@ dbnex14 Vous pouvez aussi instancier la classe plus tôt. Je ne sais pas ce que vous entendez par "il a un problème avec les paramètres publics"? –

+1

@ dbnex14 vous pouvez instancier l'instance de la classe comme new SomethingParameters {A = valeurA, D = valeurD}. Vous n'avez pas besoin de faire des surcharges de SomethingParameters .ctor –

2

Je préfère la possibilité d'utiliser une catégorie distincte pour les paramètres. Mais peut-être, comme vous l'avez dit, vous appelez déjà la méthode à plusieurs endroits et vous ne voulez pas la modifier.
Dans ce cas, vous pouvez ajouter un paramètre optionnel:

public void DoSmtg(string a, int x, double d, bool doIt = false) 

Rien ne doit changer nulle part ailleurs, sauf que vous pouvez fournir le paramètre si vous le désirez.

Si vous vous trouvez en train de faire cela, j'écrirais toujours la surcharge supplémentaire en utilisant une classe de toute façon et commencer à l'utiliser. Les paramètres facultatifs peuvent également devenir désordonnés s'ils sont trop nombreux.

+0

Merci @ScottHannen mais j'ai déjà des paramètres optionnels. Le problème reste cependant. Si je dois ajouter un nouveau paramètre, je devrai faire beaucoup de modifications. – pixel

+0

Si vous ajoutez uniquement un paramètre facultatif, les seules modifications concernent les méthodes elles-mêmes et les appelants qui transmettent le paramètre facultatif. –