2010-02-22 20 views
4

Disons que j'ai une méthode statique appelée Logger.log(), qui appelle une autre méthode statique, CurrentUser.getName(), pour obtenir des informations supplémentaires pour vous connecter:Comment facteur appel statique sur une classe

public static void log(text) { 
    String[] itemsToLog = { text, todaysDate, ipAddress, CurrentUser.getName() }; 

Maintenant, évidemment, ce n'est pas une situation idéale, en particulier avec les données statiques dans la classe CurrentUser. Mais je veux commencer à l'améliorer en réduisant les dépendances de l'enregistreur. Je préférerais que l'enregistreur n'ait aucune connaissance des concepts de niveau supérieur comme les utilisateurs. Il a juste besoin d'une liste de choses à se connecter, et ne se soucie pas de ce qu'ils sont. Donc, je veux en quelque sorte factoriser la classe CurrentUser. Mais Logger est statique, donc je ne peux pas simplement passer l'information dans son constructeur.

Quel serait un bon modèle pour factoriser des choses comme ça?

Répondre

1

Vous avez deux options:

  1. Toujours transmettre les informations à l'enregistreur
  2. Have Logger maintenir statiquement au sein de l'enregistreur (ou appeler une autre méthode)

Si vous ne voulez pas Logger pour le maintenir statiquement, et vous ne voulez pas inclure les informations supplémentaires (ou les appels) dans l'appel à chaque fois, vous pouvez créer une autre classe qui appelle Logger et transmet toutes ces informations statiques, puis change Logger pour ne pas avoir de données statiques (ou au moins ne pas appeler Cu rrentUser). Ensuite, la classe qui appelle le consignateur peut accepter CurrentUser dans son constructeur. Vous pouvez utiliser cela comme un tremplin pour un futur refactoring. Si votre langue prend en charge les méthodes d'extension ou les aides de classe, vous pouvez modifier Logger pour accepter CurrentUser en tant que paramètre, puis ajouter une méthode d'extension qui n'accepte que le texte du journal, puis transmet automatiquement CurrentUser. Cela vous permettrait de faire le changement sans changer tous les appels, bien que cela nécessiterait que la méthode d'extension soit statique. . . donc vous ne gagnez pas beaucoup de terrain.

0

Vous n'avez pas beaucoup de choix ici. Si vous ne voulez pas que le consignateur s'appuie sur CurrentUser, vous pouvez compter sur l'utilisateur final (classe de journalisation) pour insérer l'utilisateur dans le texte de journalisation, ou créer une sous-classe de logger qui connaît CurrentUser, qui peut vaincre votre but.

1

je préférerais que le Logger pas connaissance des concepts de niveau supérieur comme les utilisateurs.

Il semble que la direction dans laquelle vous souhaitez aller est de séparer la composition des messages de journal et la logique de formatage des mécanismes de journalisation. Par exemple (pardonnez mon C idiomes n):

public class WebRequestLogEntry { 

    // In some frameworks, you may get username, address, etc. from an 
    // HttpContext or similar object, simplifying this constructor 

    public WebRequestLogEntry(string message, string userName, IpAddress address) { 
     // Sets member variables 
    } 

    public string Text { 
     get { 
      // Concatenate and format member data 
     } 
    } 
} 

À partir de là, il suffit d'appeler votre enregistreur comme ceci:

Logger.log(new WebRequestLogEntry("Hi", CurrentUser.getName(), ipAddress).Text); 
2

Il me semble que votre enregistreur maintient déjà un état (par exemple, la date, l'adresse , utilisateur, etc.).

N'est-il pas logique de faire de log() un appel non statique sur un enregistreur spécifique, et d'avoir tout ce qui est important (y compris l'utilisateur) initialisé lors de la création de l'enregistreur? Vous pourriez avoir un gestionnaire de loggers que vous utiliseriez pour initialiser et ensuite obtenir des loggers spécifiques, ou simplement faire de votre logger un singleton (si tel est le cas). La logique d'obtention de l'utilisateur se trouverait alors dans le gestionnaire de loggers ou dans factory/getInstance() pour l'enregistreur, plutôt que dans l'instance de Logger elle-même.

0

Une option pourrait être de créer une nouvelle ContextProvider d'interface et obtenir votre chaîne contextuelle à partir de là

public interface ContextProvider{ 
    public List<String> getContextToLog(); 
} 
... 
public class DefaultLoggingContext implements ContextProvider{ 
    public List<String> getContextToLog(){ 
     ... 
     list.Add(CurrentUser.getName()); 
     ... 
     return list; 
    } 
} 
... 
public class Logger{ 
    private static ContextProvider contextProvider; 

    public static initiliseLogger(ContextProvider defaultProvider){ 
     contextProvider = defaultProvider; 
    } 

    public static log(String text){ 
     log(text, contextProvider); 
    } 

    public static log(String text, contextProvider){ 
     List<String> toLog = contextProvider.getContextToLog(); 
     toLog.add(text); 
} 
... 
public class ...{ 
    private ContextProvider loggingContext; // set by a constructor, factory method or a IOC container 

    private onApplicationStart(){ 
     Logger.initiliseLogger(loggingContext) 
    } 
} 

Vous pouvez prendre un peu plus loin et d'utiliser un Formatter au lieu d'un contextProvider le formateur serait chargé de prendre la chaîne d'entrée "texte" et le formatage complétement y compris l'ajout de toute session, date, heure, demande etc. Vous pouvez regarder log4* pour les implamentations complètes de cela. Sur une note de côté, je suggérerais que déplacer la méthode de log pour être une méthode d'instance n'est pas une méthode statique, ce serait un très bon coup, vous pouvez soit supporter à la fois pendant un moment avec le statique marqué comme obsolète ou vous pouvez sortir votre trouvaille et remplacez le bâton. Une caractéristique de log4 * que j'aime vraiment est la possibilité de changer la sensibilité de la journalisation en fonction de la classe ou du paquet.