76 votes

Est-ce une bonne pratique d'avoir un enregistreur en tant que singleton?

J'avais l'habitude de passer enregistreur de constructeur, comme:

public class OrderService : IOrderService {
     public OrderService(ILogger logger) {
     }
}

Mais c'est assez ennuyeux, j'ai donc utilisé une propriété pendant un certain temps:

private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
    get { return logger; }
    set { logger = value; }
}

C'est plus ennuyeux trop - il n'est pas sec, j'ai besoin de répéter dans chaque classe. Je pourrais utiliser de la classe de base, mais encore une fois - je suis en utilisant le Formulaire de classe, donc, il faudrait FormBase, etc. Donc, je pense, ce serait inconvénient d'avoir singleton avec ILogger exposés, de sorte que toute personne serait de savoir où obtenir de l'enregistreur:

    Infrastructure.Logger.Info("blabla");

Mise à JOUR: Comme Merlyn correctement remarqué, j'ai devriez le mentionner, que dans le premier et deuxième exemples que je suis à l'aide de DI.

37voto

Daniel Rose Points 8024

Je mets une instance de consignateur dans mon conteneur d'injection de dépendance, qui l'injecte ensuite dans les classes qui en ont besoin.

34voto

Merlyn Morgan-Graham Points 31815

C'est plus ennuyeux trop - il n'est pas SEC

C'est vrai. Mais il ya seulement tellement que vous pouvez faire pour un transversales préoccupation qui imprègne chaque type que vous avez. Vous devez utiliser l'enregistreur de partout, de sorte que vous devez avoir la propriété sur ces types.

Donc permet de voir ce que nous pouvons faire à ce sujet.

Singleton

Les Singletons sont terribles <flame-suit-on>.

Je recommande de rester avec la propriété d'injection comme vous l'avez fait avec votre deuxième exemple. C'est le meilleur de l'affacturage vous pouvez le faire sans avoir recours à la magie. Il est préférable d'avoir une dépendance explicite que de le cacher par un singleton.

Mais si les singletons de gagner beaucoup de temps, y compris tous les refactoring que vous aurez jamais à faire (boule de cristal!), Je suppose que vous pourriez être en mesure de vivre avec eux. Si jamais il y avait une utilisation d'un Singleton, c'est peut-être elle. Gardez à l'esprit le coût si vous jamais voulez changer votre esprit sera aussi élevé qu'il l'obtient.

Si vous faites cela, découvrez les réponses des autres à l'aide de l' Registry modèle (voir la description), et ceux de l'inscription d'un (resetable) singleton usine plutôt que d'un singleton journal instance.

Il existe d'autres alternatives qui pourraient tout aussi bien sans pour autant compromettre, de sorte que vous devriez les vérifier en premier.

Visual Studio extraits de code

Vous pouvez utiliser Visual Studio extraits de code pour accélérer l'entrée de ce code répétitif. Vous serez en mesure de taper quelque chose comme loggeronglet, et le code va apparaître comme par magie pour vous.

À l'aide de l'AOP pour se SÉCHER

Vous pourriez éliminer un peu de cette propriété de l'injection de code à l'aide d' une Programmation Orientée Aspects (AOP) cadre comme PostSharp de générer automatiquement certains.

Il pourrait ressembler à ceci lorsque vous avez terminé:

[InjectedLogger]
public ILogger Logger { get; set; }

Vous pouvez également utiliser leur méthode de traçage de l'exemple de code automatiquement la trace de la méthode d'entrée et de sortie de code, ce qui pourrait éliminer le besoin d'ajouter un peu de l'enregistreur de propriétés de tous ensemble. Vous pouvez appliquer l'attribut à un niveau de classe, ou de l'espace de large:

[Trace]
public class MyClass
{
    // ...
}

// or

#if DEBUG
[assembly: Trace( AttributeTargetTypes = "MyNamespace.*",
    AttributeTargetTypeAttributes = MulticastAttributes.Public,
    AttributeTargetMemberAttributes = MulticastAttributes.Public )]
#endif

24voto

sll Points 30638

Bonne question. Je crois que dans la plupart des projets de logger est un singleton.

Quelques idées viennent à mon esprit:

  • Utilisation ServiceLocator (ou d'une autre Injection de Dépendance conteneur si vous utilisez déjà un) qui vous permet de partager enregistreur de tous les services/classes, de cette façon, vous pouvez instancier enregistreur ou même plusieurs enregistreurs et les partager via ServiceLocator qui serait évidemment un singleton, une sorte d' Inversion de Contrôle. Cette approche vous donne beaucoup de flexibilité sur un enregistreur de l'instanciation et l'initialisation du processus.
  • Si vous avez besoin d'un enregistreur de presque partout dans le monde - mettre en œuvre des méthodes d'extension pour Object type de sorte que chaque classe pourrait appeler enregistreur de méthodes comme l' LogInfo(), LogDebug(), LogError()

15voto

Anders Abel Points 36203

Un singleton est une bonne idée. Une idée encore meilleure consiste à utiliser le modèle de registre , qui donne un peu plus de contrôle sur l’instanciation. À mon avis, le modèle singleton est trop proche des variables globales. Avec un registre gérant la création ou la réutilisation d’objets, il est possible d’apporter des modifications aux règles d’instanciation.

Le registre lui-même peut être une classe statique pour donner une syntaxe simple pour accéder au journal:

 Registry.Logger.Info("blabla");
 

9voto

jgauffin Points 51913

Une plaine singleton n'est pas une bonne idée. Cela rend difficile de remplacer l'enregistreur. J'ai tendance à utiliser des filtres pour mon enregistreurs (certains "bruits" de classes peuvent se connecter uniquement des avertissements/erreurs).

J'utilise le pattern singleton est combiné avec le modèle de proxy pour l'enregistreur de l'usine:

public class LogFactory
{
    private static LogFactory _instance;

    public static void Assign(LogFactory instance)
    {
        _instance = instance;
    }

    public static LogFactory Instance
    {
        get { _instance ?? (_instance = new LogFactory()); }
    }

    public virtual ILogger GetLogger<T>()
    {
        return new SystemDebugLogger();
    }
}

Cela me permet de créer un FilteringLogFactory ou juste un SimpleFileLogFactory , sans modification du code (et donc se conformer à Ouvert/Fermé).

Exemple d'extension

public class FilteredLogFactory : LogFactory
{
    public override ILogger GetLogger<T>()
    {
        if (typeof(ITextParser).IsAssignableFrom(typeof(T)))
            return new FilteredLogger(typeof(T));

        return new FileLogger(@"C:\Logs\MyApp.log");
    }
}

Et l'utilisation de la nouvelle usine

// and to use the new log factory (somewhere early in the application):
LogFactory.Assign(new FilteredLogFactory());

Dans votre classe qui doit ouvrir une session:

public class MyUserService : IUserService
{
    ILogger _logger = LogFactory.Instance.GetLogger<MyUserService>();

    public void SomeMethod()
    {
        _logger.Debug("Welcome world!");
    }
}

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