73 votes

C #: événements ou une interface d'observateur? Avantages / inconvénients?

J'ai le suivant (simplifié):

 interface IFindFilesObserver
{
    void OnFoundFile(FileInfo fileInfo);
    void OnFoundDirectory(DirectoryInfo directoryInfo);
}

class FindFiles
{
    IFindFilesObserver _observer;

    // ...
}
 

... et je suis en conflit. C'est en gros ce que j'aurais écrit en C ++, mais C # a des événements. Devrais-je changer le code pour utiliser des événements ou devrais-je le laisser seul?

Quels sont les avantages ou les inconvénients des événements par rapport à une interface d'observateur traditionnelle?

79voto

Scott Langham Points 17447

Prenons un événement à une interface de rappel où l'interface a une seule méthode.

Seule crochet événements dont vous avez besoin
Avec les événements que vous avez seulement besoin de mettre en œuvre des gestionnaires pour les événements qui vous intéressent dans la manipulation. Dans l'observateur de l'interface de modèle, vous auriez à mettre en œuvre toutes les méthodes dans l'ensemble de l'interface, y compris la mise en œuvre de la méthode d'organes pour les types de notifications que vous n'avez pas de soins sur la manipulation. Dans votre exemple, vous avez toujours à mettre en œuvre OnFoundDirectory et OnFoundFile, même si vous ne se soucient l'un de ces événements.

Moins d'entretien
Une autre bonne chose à propos des événements, vous pouvez en ajouter un nouveau à une classe particulière de sorte que cela va augmenter, et vous n'avez pas à changer tous les observateurs. Tandis que si vous voulez ajouter une nouvelle méthode à une interface, vous devez aller autour de chaque classe qui implémente déjà que l'interface et de mettre en œuvre la nouvelle méthode dans chacun d'eux. Avec un événement, vous avez seulement besoin de modifier les classes qui veulent réellement faire quelque chose en réponse à la nouvelle de l'événement que vous ajoutez.

Le modèle est construit dans la langue de sorte que tout le monde sait comment l'utiliser
Les événements sont idiomatiques, en ce que lorsque vous voyez un événement, vous savez comment l'utiliser. Avec un observateur de l'interface, les gens ont souvent de mettre en œuvre différentes façons de s'inscrire pour recevoir des notifications ainsi que le raccordement de l'observateur.. avec des événements bien que, une fois que vous avez appris à vous inscrire et utiliser une (avec l'opérateur+=), le reste sont tous les mêmes.

Des Pros pour les interfaces
Je n'ai pas beaucoup de pros pour des interfaces. Je suppose qu'ils se forcer quelqu'un à afin de mettre en œuvre toutes les méthodes de l'interface. Mais, vous ne pouvez pas vraiment forcer quelqu'un à mettre en œuvre toutes ces méthodes correctement, donc je ne pense pas qu'il y a beaucoup de valeur sur ce.

La syntaxe
Certaines personnes n'aiment pas la façon dont vous devez déclarer un type délégué pour chaque événement. Aussi, la norme de gestionnaires d'événements dans le .Net framework suivez ces paramètres: (object sender, EventArgs args). Comme expéditeur ne pas spécifier un type particulier, vous avez à bas-en fonte si vous voulez l'utiliser. C'est souvent fine, dans la pratique, si elle ne se sent pas tout à fait juste parce que vous êtes de perdre la protection du système de type statique. Mais, si vous mettez en œuvre vos propres événements et de ne pas suivre les .Net framework convention sur cela, vous pouvez utiliser le bon type pour que les bas-casting n'est pas nécessaire.

32voto

Frederik Gheysels Points 36354

Hmm, les événements peuvent être utilisés pour implémenter le modèle Observer. En fait, l’utilisation d’événements peut être considérée comme une autre implémentation du modèle à motif observateur.

12voto

Alex Burtsev Points 4251
  • Les événements sont plus difficiles à se propager à travers la chaîne d'objets, par exemple, si vous utilisez FAÇADE de modèle ou de déléguer le travail à d'autres classe.
  • Vous devez être très prudent avec désabonnement des événements pour permettre l'objet à ordures.
  • Les événements sont 2x fois plus lent que la simple appel de fonction, 3x plus lent si vous n'null check sur chaque augmentation, et copie délégué d'événement avant null check et l'invocation à faire thread-safe.

  • Également lire MSDN sur les nouvelles (4,0) IObserver<T> interface.

Considérons cet exemple:

using System;

namespace Example
{
    //Observer
    public class SomeFacade
    {
        public void DoSomeWork(IObserver notificationObject)
        {
            Worker worker = new Worker(notificationObject);
            worker.DoWork();
        }
    }
    public class Worker
    {
        private readonly IObserver _notificationObject;
        public Worker(IObserver notificationObject)
        {
            _notificationObject = notificationObject;
        }
        public void DoWork()
        {
            //...
            _notificationObject.Progress(100);
            _notificationObject.Done();
        }
    }
    public interface IObserver
    {
        void Done();
        void Progress(int amount);
    }

    //Events
    public class SomeFacadeWithEvents
    {
        public event Action Done;
        public event Action<int> Progress;

        private void RaiseDone()
        {
            if (Done != null) Done();
        }
        private void RaiseProgress(int amount)
        {
            if (Progress != null) Progress(amount);
        }

        public void DoSomeWork()
        {
            WorkerWithEvents worker = new WorkerWithEvents();
            worker.Done += RaiseDone;
            worker.Progress += RaiseProgress;
            worker.DoWork();
            //Also we neede to unsubscribe...
            worker.Done -= RaiseDone;
            worker.Progress -= RaiseProgress;
        }
    }
    public class WorkerWithEvents
    {
        public event Action Done;
        public event Action<int> Progress;

        public void DoWork()
        {
            //...
            Progress(100);
            Done();
        }
    }
}

8voto

ShuggyCoUk Points 24204

Certains autres avantages d'événements.

  • Vous bénéficiez d'une véritable multidiffusion le comportement des pour gratuit.
  • Si vous modifiez les abonnés d'un événement, en réponse à cet événement que le comportement est bien défini
  • Ils peuvent être l'introspection (réfléchi) facilement et de manière cohérente
  • Outil de la chaîne de soutien pour les événements (tout simplement parce qu'ils sont l'idiome dans .net)
  • Vous avez la possibilité d'utiliser l'api asynchrones il fournit

Vous pouvez atteindre tous ces objectifs (à l'exception de la chaîne d'outils) vous-même, mais il est étonnamment difficile. Par exemple: Si vous utilisez une variable de membre comme une List<> pour stocker la liste des observateurs. Si vous utilisez une boucle foreach pour parcourir il alors toute tentative d'ajouter ou de supprimer un abonné dans un délai d'un des OnFoo() la méthode des rappels déclenchera une exception, à moins que vous écrire plus de code pour gérer proprement.

8voto

Lasse V. Karlsen Points 148037

Les Pros de l'interface de la solution:

  • Si vous ajoutez des méthodes, des observateurs actuels besoins pour mettre en œuvre ces méthodes. Cela signifie que vous avez le moins de chance de l'oublier au fil des observateurs actuels à de nouvelles fonctionnalités. Vous pouvez bien sûr mettre en œuvre les méthodes vides qui signifie que vous avez le luxe de ne rien faire en réponse à certains "événements". Mais vous n'aurez pas si facilement oublier.
  • Si vous utilisez la mise en œuvre explicite, vous obtiendrez également des erreurs de compilation dans l'autre sens, si vous supprimez ou modifiez les interfaces, les observateurs ont alors leur mise en œuvre permettra d'arrêter la compilation.

Inconvénients:

  • Plus pensé a aller dans la planification, car un changement dans l'observateur de l'interface peut appliquer des modifications sur votre solution, qui pourrait avoir besoin de planification différents. Depuis un simple événement est facultatif, peu ou aucun autre code n'a changer, à moins que d'autres le code de réagir à l'événement.

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