Une méthode «démarrer», «exécuter» ou «exécuter» est-elle une bonne pratique?

30

Je travaille actuellement sur une base de code qui a de nombreuses classes qui implémentent une méthode Start. Cela me semble être une construction en deux phases, que j'avais toujours considérée comme une mauvaise pratique. Je ne peux pas faire la différence entre cela et un constructeur.

Quand est-il approprié d'utiliser une méthode de démarrage au lieu d'une construction d'objet normale?

Quand devrais-je préférer utiliser le constructeur?

Edit: Je ne pense pas que ce soit pertinent mais le langage de programmation est C #, il pourrait également s'appliquer à Java ou C ++

Dave Hillier
la source
3
Pourriez-vous ajouter un peu plus de contexte? La langue? Fileté vs fil unique? différence entre startet le constructeur? etc ...
@MichaelT Je peux voir pourquoi vous posez la question, mais je m'intéresse au principe général derrière quand c'est approprié. Je crains que si je donnais des exemples spécifiques de la base de code sur laquelle je travaille, les réponses seraient trop centrées sur les détails et non sur mes questions spécifiques.
Dave Hillier
2
@DaveHillier Par exemple, en perl, il est courant (et bon) d'avoir une initméthode quelconque en dehors de la newfonction - perldoc.perl.org/perlobj.html . Les idiomes d'une langue peuvent bien fonctionner là-bas et pas dans d'autres langues.
1
Des exemples de classes avec des Startméthodes dans les API communes incluent les threads et les chronomètres.
luiscubal
1
Comptez-moi parmi ceux qui ont besoin d'un exemple de code pour comprendre ce que vous demandez réellement.
user16764

Réponses:

44

Une Start()méthode (comme Run(), Execute()ou quelque chose de similaire) est appropriée lorsque le coût de construction de l'objet est faible, mais le coût de l' utilisation est élevée. Par exemple: Une classe qui encapsule un algorithme d'optimisation du meilleur chemin. Il est trivial de le configurer avec un ensemble de paramètres ( Xcarrés par Ycarrés, avec une telle méthode d'évaluation), mais son exécution peut prendre un certain temps. Si vous souhaitez créer 20 de ces objets, vous souhaiterez peut-être retarder l'exécution jusqu'à ce qu'ils soient tous créés - cela vous permet par exemple de les paralléliser plus facilement.

Alternativement, cela pourrait être utile lorsque vous ne savez pas quand l'objet sera nécessaire pour démarrer - peut-être parce qu'il est basé sur une entrée utilisateur ou une logique qui sélectionne dans une liste de possibilités.

Cela suppose, bien sûr, que Start()c'est la méthode utile sur l'objet, et non l'équivalent d'une Initialize()méthode. Si c'est juste un moyen supplémentaire de définir plus de paramètres, cela ne devrait pas exister.

Bobson
la source
1
Une autre utilisation d'une méthode de démarrage est lorsque l'action effectuée crée également un nouveau thread de travail ou un minuteur. Le constructeur ne doit pas faire ce genre de travail lourd ou générer des effets secondaires importants (comme créer un nouveau thread).
Ziv
50

Code Complete (et de nombreuses autres ressources d'ingénierie logicielle) met l'accent sur la correspondance de vos classes avec des objets du monde réel. Je crois que la raison fondamentale de cela est qu'il rend plus probable que vous compreniez vraiment ce que vous mettez en œuvre, plutôt que de pirater une idée intangible.

Si vous êtes abonné à cette théorie, je ne vois rien de mal à ajouter une Start()méthode à une classe qui devrait, si elle était un véritable objet, avoir également un état de repos. Si cela n'a aucun sens que votre objet existe lorsqu'il n'est pas en cours d'exécution (ou n'a aucun sens pour que votre objet fonctionne), je dirais que c'est une mauvaise pratique.

Dan Albert
la source
16
Une bonne analogie. Il convient de noter que cela Start()pourrait correspondre à un interrupteur marche / arrêt (comme un interrupteur) qui devrait alors avoir un Stop(), ou à un bouton-poussoir (comme le bouton Imprimer sur une photocopieuse) où il démarre et s'exécute jusqu'à ce qu'il soit terminé.
Bobson
3
+1 bien dit et bienvenue à P.SE, des réponses comme celle-ci sont un bon début.
Jimmy Hoffa
14

Vous pouvez utiliser l' initialisation paresseuse.

En programmation informatique, l'initialisation paresseuse est la tactique de retarder la création d'un objet, le calcul d'une valeur ou un autre processus coûteux jusqu'à la première fois qu'il est nécessaire.

De cette façon, vous évitez le couplage temporel, ce qui signifie que le consommateur de votre classe doit appeler certaines méthodes dans un certain ordre. Avoir à appeler en start()premier est un moyen de savoir comment fonctionne la classe en interne, ce qui est mauvais car vous pourriez changer cela à l'avenir.

Retardez l'initialisation coûteuse jusqu'à ce qu'elle soit nécessaire.

Exemple:

public class FooClass{

    private ExpensiveResource resource;
    private CheapResource cheap;

    public  FooClass(String someParameter){
        // constructor: initialize CheapResource cheap 
            // but NOT ExpensiveResource resource
    }

    public ExpensiveResource getExpensiveResource(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource
    }

    public String getExpensiveResourceName(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource.getName();
    }   

    public CheapResource getCheapResource(){
        return this.cheap;
    }

    private initializeExpensiveResource(){
        // do expensive initialization of field "resource"
    }

}

public class Test{
    public static void main (String args[]){

        FooClass foo = new FooClass("some string");
        CheapResource cr = foo.getCheapResource();
        String s = foo.getExpensiveResourceName(); 
          // just now is the expensive resource initialized

    }
}
Tulains Córdova
la source
5
Un autre avantage de l'initialisation paresseuse qui mérite d'être noté est que cela prend très peu d'efforts pour le former en un proxy virtuel . Selon la situation, cela peut être très utile pour afficher quelque chose en attendant le chargement d'une ressource (particulièrement utile pour des choses comme des images distantes). Sur la base de la question initiale, je ne pense pas que ce soit vraiment ce que le PO recherchait, mais j'ai pensé que cela valait la peine d'être mentionné.
Dan Albert
@DanAlbert vous avez raison ce n'est pas ce que je demandais mais toujours intéressant
Dave Hillier