As a factor of static call from class

Let's say I have a static Logger.log () method that calls another static CurrentUser.getName () method to get additional information for the log:

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

Now, obviously, this is not an ideal situation, especially with static data in the CurrentUser class. But I want to start improving it by reducing Logger dependencies. I would prefer Logger not to know about higher level concepts like users. He just needs a list of things to register, and they don't care what that is.

So, I want to somehow separate the CurrentUser class. But Logger is static, so I can’t just pass the information to my constructor.

What would be a good template for factoring such things?

+4
source share
5 answers

It seems to me that your Logger already supports a certain state (for example, date, address, user, etc.).

Doesn't it make sense to make log () a non-static call on a specific logger and initialize all the relevant ones (including the user) when the registrar is first created? You may have a log manager that you would use to initialize and then to get certain registrars, or just make your journal one single (if it is). The user acquisition logic will then be in the log manager or in factory / getInstance () for the logger, and not in the Logger instance itself.

+2
source

You have two options:

  • Always pass information to Logger
  • The logger stores it statically inside the Logger (or calls another method)

If you do not want Logger to support it statically, and you do not want to include additional information (or calls) in the call each time, then you can create another class that calls Logger and passes all these static information, then change Logger to no static data (or at least not called CurrentUser). Then the class that calls the log can accept CurrentUser in its constructor.

You can use this as a stepping stone for future refactoring.

If your language supports extension methods or class helpers, you can change Logger to accept CurrentUser as a parameter, and then add an extension method that accepts only log text and then automatically passes CurrentUser. This will allow you to make changes without changing all the calls, although this requires the extension method to be static. So you don't get much land.

+1
source

I would prefer that Logger does not have any knowledge of higher-level concepts as users.

It looks like the direction you might want is to separate the log message structure and formatting logic from the registration mechanics. For example (have mercy on my C # idioms):

 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 } } } 

From there, just call your registrar as follows:

 Logger.log(new WebRequestLogEntry("Hi", CurrentUser.getName(), ipAddress).Text); 
+1
source

You don't have many options here. If you don't want the logger to rely on CurrentUser, you can rely on the end user (the logging class) to insert the user into the logging text, or create a subclass of the log class that knows about CurrentUser that can defeat your goal.

0
source

One option would be to create a new ContextProvider interface and get your context string from it

 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) } } 

You can do this even further and use Formatter instead of contextProvider, the formatter will be responsible for entering the string "text" and formatting it completely, including adding information about the session, date, time, request, etc. You can look at log4 * for a complete understanding of this.

On the side of the note, I would suggest that moving the log method as an instance method, rather than a static method, would be a very good step, you can either support it for a while, or statically marked as deprecated, or you can find and replace the stick. One log4 * feature that I really like is the ability to change logging sensitivity based on a class or package.

0
source

Source: https://habr.com/ru/post/1302050/


All Articles