2017-03-11 1 views
0

Donc je me demande un peu quelle est la meilleure pratique ici.Paquets Golang et l'utilisation des variables à travers les paquets

J'ai une application avec plusieurs sous-paquets, certains exigent l'accès à l'enregistreur je dans le paquet principal, parce que j'utiliser un enregistreur personnalisé avec des couleurs et des horodateurs, etc.

est la seule façon d'y parvenir en injectant c'est comme ça? (En supposant Handler est dans un sous-paquetage appelé commande)

type Handler struct { 
    logger logging.Logger 
} 

func NewHandler(logger logging.Logger) Handler { 
    return Handler{ 
     logger: logger, 
    } 
} 

handler := command.NewHandler(logger) 

Cette question que j'ai avec cela est que le test devient ennuyeux car je dois se moquer de l'enregistreur pour les tests. Je pensais à juste retour des erreurs qui doivent être enregistrées et permettent la principale package deal avec eux, mais j'aimerais exécuter certains async fonctionnent comme si

go handler.HandleMessage(msg) 

idk Alors, comment gérer les erreurs de fonctions asynchrones ou si C'est même possible.

Alors, y a-t-il une meilleure pratique pour faire ce que je veux?

Répondre

1

Quelques réflexions sur ce point:

  1. Injecter la ressource (enregistreur) est la meilleure façon de le faire à mon avis. Le référencement direct d'une variable globale est certainement possible, mais rend votre code difficile à modifier.
  2. Si vous vous connectez.Logger est un type concret, alors vous pouvez le faire fonctionner quand il est nul, ce qui vous permet de passer l'initialisation dans vos tests.
  3. Vous pouvez absolument gérer vos erreurs dans les appels asynchrones.

Sur ce dernier point, vous pouvez utiliser les fonctions anonymes pour ajouter la gestion des erreurs supplémentaires sur le site d'appel:

go func() { 
     err := handler.HandleMessage(msg) 
     // err handling/logging here 
}() 

Si vous pouvez transmettre des erreurs jusqu'à significative sur le site d'appel qui a lancé l'appel alors je préfère pour ce faire à chaque fois. Vous devez garder à l'esprit que vous utilisez toujours un goroutine distinct lorsque vous revenez de HandleMessage().

+0

Merci beaucoup! La fonction anonyme est une excellente idée. Pourriez-vous élaborer sur 2? Je ne peux pas passer à zéro. À quoi ressemble un "type concret"? – gempir

+0

Si logging.Logger est une interface, vous devez en passer une implémentation à NewHandler pour y passer des appels. Si d'un autre côté, c'est une structure {} avec une méthode Log(), alors dans la fonction Log (Log * Logger) Log (msg string), vous pouvez vérifier si log == nil et retourner si c'est le cas. Cela signifie qu'un Logger vide (par exemple créer simplement Handler {}) est toujours valide - vous n'avez pas besoin de l'initialiser. –

+0

Ahh d'accord ça a du sens. Dans mon cas, logging.Logger est une interface d'une bibliothèque tierce donc je devrais écrire un wrapper autour – gempir