web-dev-qa-db-fra.com

Classe avec une seule méthode - meilleure approche?

Supposons que je possède un cours destiné à remplir une seule fonction. Après avoir exécuté la fonction, il peut être détruit. Y a-t-il une raison de préférer l'une de ces approches?

// Initialize arguments in constructor
MyClass myObject = new MyClass(arg1, arg2, arg3);
myObject.myMethod();

// Pass arguments to method
MyClass myObject = new MyClass();
myObject.myMethod(arg1, arg2, arg3);

// Pass arguments to static method
MyClass.myMethod(arg1, arg2, arg3);

J'étais intentionnellement vague sur les détails, pour essayer d'obtenir des directives pour différentes situations. Mais je n'avais pas vraiment à l'esprit des fonctions de bibliothèque simples comme Math.random (). Je pense plus aux classes qui effectuent une tâche spécifique et complexe, mais qui ne nécessitent qu'une méthode (publique) pour le faire.

163
JW.

J'aimais les classes utilitaires remplies de méthodes statiques. Ils ont procédé à une excellente consolidation des méthodes d'assistance qui, autrement, auraient été générées, entraînant redondance et maintenance. Ils sont très faciles à utiliser, aucune instanciation, aucune élimination, rien que du feu. J'imagine que c'était ma première tentative involontaire de créer une architecture orientée service - de nombreux services sans état qui faisaient simplement leur travail et rien d'autre. Cependant, à mesure que le système se développe, les dragons arrivent.

Polymorphisme
Disons que nous avons la méthode UtilityClass.SomeMethod qui bourdonne joyeusement. Tout à coup, nous devons modifier légèrement les fonctionnalités. La plupart des fonctionnalités sont les mêmes, mais nous devons néanmoins modifier quelques éléments. Si cela n’avait pas été une méthode statique, nous pourrions créer une classe de dérivés et modifier le contenu de la méthode selon les besoins. Comme c'est une méthode statique, nous ne pouvons pas. Bien sûr, si nous devons simplement ajouter des fonctionnalités avant ou après l’ancienne méthode, nous pouvons créer une nouvelle classe et appeler l’ancienne à l’intérieur de celle-ci - mais c’est tout simplement dégoûtant.

Problèmes d'interface
Les méthodes statiques ne peuvent pas être définies via des interfaces pour des raisons logiques. Et comme nous ne pouvons pas redéfinir les méthodes statiques, les classes statiques sont inutiles lorsque nous devons les transmettre par leur interface. Cela nous rend incapables d'utiliser des classes statiques dans le cadre d'un modèle de stratégie. Nous pourrions corriger quelques problèmes en en passant des délégués à la place des interfaces .

Test
Cela va fondamentalement de pair avec les problèmes d’interface mentionnés ci-dessus. Notre capacité d'interchanger les implémentations étant très limitée, nous aurons également du mal à remplacer le code de production par le code de test. Encore une fois, nous pouvons les envelopper mais cela nous demandera de modifier de grandes parties de notre code simplement pour pouvoir accepter des wrappers à la place des objets réels.

Crée des blobs
Comme les méthodes statiques sont généralement utilisées comme méthodes d’utilité et que celles-ci ont généralement des objectifs différents, nous allons rapidement nous retrouver avec une grande classe remplie de fonctionnalités non cohérentes - idéalement, chaque classe doit avoir un seul objectif. dans le système. Je préférerais de beaucoup avoir cinq fois les classes tant que leurs objectifs sont bien définis.

Paramètre de fluage
Pour commencer, cette petite méthode statique mignonne et innocente pourrait prendre un seul paramètre. À mesure que la fonctionnalité augmente, deux nouveaux paramètres sont ajoutés. Bientôt d'autres paramètres, facultatifs, sont ajoutés. Nous créons donc des surcharges de la méthode (ou ajoutons simplement des valeurs par défaut, dans les langues qui les prennent en charge). D'ici peu, nous avons une méthode qui prend 10 paramètres. Seuls les trois premiers sont vraiment nécessaires, les paramètres 4 à 7 sont facultatifs. Mais si le paramètre 6 est spécifié, vous devez également renseigner 7-9 ... Si nous avions créé une classe dans le seul but de faire ce que cette méthode statique a fait, nous pourrions résoudre ce problème en prenant les paramètres requis dans le fichier. constructeur, et en permettant à l'utilisateur de définir des valeurs facultatives via des propriétés ou des méthodes permettant de définir plusieurs valeurs interdépendantes en même temps. En outre, si une méthode a atteint une telle complexité, elle doit de toute façon appartenir à sa propre classe.

Demander aux consommateurs de créer une instance de classes sans raison
L’un des arguments les plus courants est la suivante: pourquoi demander aux consommateurs de notre classe de créer une instance pour invoquer cette méthode unique, sans utiliser l’instance par la suite? Créer une instance d'une classe est une opération très très économique dans la plupart des langues, la rapidité n'est donc pas un problème. L'ajout d'une ligne de code supplémentaire au consommateur représente un faible coût pour poser les bases d'une solution beaucoup plus facile à gérer dans le futur. Enfin, si vous souhaitez éviter de créer des instances, créez simplement un wrapper singleton de votre classe qui permette une réutilisation facile - bien que cela rende l'exigence que votre classe soit sans état. Si ce n'est pas sans état, vous pouvez toujours créer des méthodes de wrapper statiques qui gèrent tout, tout en vous offrant tous les avantages à long terme. Enfin, vous pouvez également créer une classe masquant l'instanciation comme s'il s'agissait d'un singleton: MyWrapper.Instance est une propriété qui renvoie simplement new MyClass ();

Seul un Sith traite en absolu
Bien sûr, il y a des exceptions à mon aversion pour les méthodes statiques. Les vraies classes d'utilitaires qui ne posent aucun risque de gonflement constituent d'excellents cas pour les méthodes statiques - System.Convert par exemple. Si votre projet est unique et ne nécessite aucune maintenance future, l'architecture globale n'est pas très importante - statique ou non statique, peu importe - la vitesse de développement l'est toutefois.

Normes, normes, normes!
L'utilisation de méthodes d'instance ne vous empêche pas d'utiliser également des méthodes statiques, et inversement. Tant que la différenciation est raisonnée et normalisée. Il n’ya rien de pire que de regarder une couche d’entreprise reposant sur différentes méthodes de mise en œuvre.

256
Mark S. Rasmussen

Je préfère la voie statique. Comme la classe ne représente pas un objet, il n’a aucun sens de faire une instance de celui-ci.

Les classes qui n'existent que pour leurs méthodes doivent rester statiques.

86
jjnguy

S'il n'y a aucune raison de créer une instance de la classe afin d'exécuter la fonction, utilisez l'implémentation statique. Pourquoi obliger les consommateurs de cette classe à créer une instance alors qu’elle n’est pas nécessaire.

17
Ray Jezek

Si vous n'avez pas besoin de sauvegarder l'objet state de l'objet, vous n'avez pas besoin de l'instancier en premier lieu. Je choisirais la méthode statique unique à laquelle vous transmettez les paramètres.

Je voudrais également mettre en garde contre une classe utils géante qui a des dizaines de méthodes statiques sans rapport. Cela peut être désorganisé et difficile à manier rapidement. Il est préférable d'avoir plusieurs classes, chacune avec peu de méthodes associées.

15
Bill the Lizard

Je dirais que le format de méthode statique serait la meilleure option. Et je rendrais la classe statique également, ainsi vous ne craindriez pas de créer accidentellement une instance de la classe.

6
Nathen Silver

Je ne sais vraiment pas ce qu’est la situation ici, mais j’envisagerais de la mettre comme méthode dans l’une des classes auxquelles arg1, arg2 ou arg3 appartient - Si vous pouvez dire sémantiquement qu’une de ces classes serait propriétaire du méthode.

5
Chris Cudmore

Je dirais qu'il est difficile de répondre sur la base des informations fournies.

Mon instinct est que si vous voulez juste avoir une méthode et que vous allez jeter la classe immédiatement, faites-en une classe statique qui prend tous les paramètres.

Bien sûr, il est difficile de dire exactement pourquoi vous devez créer une classe unique juste pour cette méthode. Est-ce la situation typique de la "classe utilitaire" comme le supposent la plupart des gens? Ou bien implémentez-vous une sorte de classe de règles, dont il pourrait y en avoir davantage à l'avenir.

Par exemple, avoir cette classe soit plugable. Ensuite, vous voudriez créer une interface pour votre méthode, puis tous les paramètres passés dans l'interface plutôt que dans le constructeur, mais vous ne voudriez pas que ce soit statique.

4
Nick

Votre cours peut-il être rendu statique?

Si tel est le cas, alors j'en ferais une classe 'Utilitaires' dans laquelle je mettrais toutes mes classes à fonction unique.

3
Robert

Pour les applications simples et les internal aides, j'utiliserais une méthode statique. Pour les applications avec des composants, j'aime beaucoup le Managed Extensibility Framework . Voici un extrait d'un document que j'écris pour décrire les modèles que vous trouverez sur toutes mes API.

  • Prestations de service
    • Défini par un I[ServiceName]Service interface.
    • Exporté et importé par le type d'interface.
    • L'implémentation unique est fournie par l'application hôte et consommée en interne et/ou par des extensions.
    • Les méthodes sur l'interface de service sont thread-safe.

À titre d'exemple artificiel:

public interface ISettingsService
{
    string ReadSetting(string name);

    void WriteSetting(string name, string value);
}

[Export]
public class ObjectRequiringSettings
{
    [Import]
    private ISettingsService SettingsService
    {
        get;
        set;
    }

    private void Foo()
    {
        if (SettingsService.ReadSetting("PerformFooAction") == bool.TrueString)
        {
            // whatever
        }
    }
}
3
Sam Harwell

Si cette méthode est sans état et que vous n'avez pas besoin de la transmettre, il est plus logique de la définir comme statique. Si vous N'AVEZ PAS besoin de transmettre la méthode, vous pouvez envisager d'utiliser délégué plutôt que l'une de vos autres approches proposées.

3
Joel Wietelmann

Je voudrais juste tout faire dans le constructeur. ainsi:

new MyClass(arg1, arg2, arg3);// the constructor does everything.

ou

MyClass my_object(arg1, arg2, arg3);
2
yigal

je pense que si les propriétés de votre classe ou l'instance de la classe ne seront pas utilisées dans les constructeurs ou dans vos méthodes, il n'est pas suggéré que les méthodes soient conçues comme des modèles "statiques". méthode statique doit toujours être pensé de manière "aide".

0
user7545070

Une autre question importante à prendre en compte est de savoir si le système fonctionnerait dans un environnement multithread et s'il serait thread-safe d'avoir une méthode statique ou des variables ...

Vous devez faire attention à l'état du système.

0
NZal

Vous pourrez peut-être éviter la situation tous ensemble. Essayez de refactoriser pour que vous obteniez arg1.myMethod1(arg2, arg3). Échangez arg1 avec arg2 ou arg3 si cela a plus de sens.

Si vous n'avez pas le contrôle sur la classe de arg1, décorez-la:

class Arg1Decorator
    private final T1 arg1;
    public Arg1Decorator(T1 arg1) {
        this.arg1 = arg1;
    }
    public T myMethod(T2 arg2, T3 arg3) {
        ...
    }
 }

 arg1d = new Arg1Decorator(arg1)
 arg1d.myMethod(arg2, arg3)

Le raisonnement est le suivant: en POO, les données et les méthodes de traitement de ces données vont de pair. De plus, vous bénéficiez de tous les avantages mentionnés par Mark.

0
Hugo Wood