Как вынести статический вызов из класса - PullRequest
4 голосов
/ 22 февраля 2010

Допустим, у меня есть статический метод, называемый Logger.log (), который вызывает другой статический метод, CurrentUser.getName (), чтобы получить дополнительную информацию для регистрации:

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

Теперь, очевидно, это не идеальная ситуация, особенно со статическими данными в классе CurrentUser. Но я хочу начать улучшать его, уменьшив зависимости Logger. Я бы предпочел, чтобы Logger не обладал знаниями о понятиях более высокого уровня, таких как пользователи. Ему просто нужен список вещей для входа, и ему все равно, какие они есть.

Итак, я хочу как-то выделить класс CurrentUser. Но Logger статичен, поэтому я не могу просто передать информацию в его конструктор.

Какой будет хороший пример для разложения таких вещей?

Ответы [ 5 ]

2 голосов
/ 22 февраля 2010

Мне кажется, что ваш регистратор уже поддерживает какое-то состояние (например, дата, адрес, пользователь и т. Д.).

Не имеет ли смысла делать log () нестатическим вызовом для конкретного регистратора и инициализировать все релевантное (включая пользователя) при первом создании регистратора? У вас может быть диспетчер логгеров, который вы будете использовать для инициализации и последующего получения определенных логгеров, или просто сделаете свой логгер одиночным (если это так). Логика получения пользователя будет тогда в менеджере регистраторов или в factory / getInstance () для регистратора, а не в самом экземпляре Logger.

1 голос
/ 22 февраля 2010

Я бы предпочел, чтобы у Logger не было любое знание концепций более высокого уровня как пользователи.

Звучит так, что вы, возможно, захотите пойти в том, чтобы отделить состав сообщения логики и логику форматирования от механизма ведения журнала. Например (простите мои идиомы C #):

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

Оттуда просто позвоните своему логгеру так:

Logger.log(new WebRequestLogEntry("Hi", CurrentUser.getName(), ipAddress).Text);
1 голос
/ 22 февраля 2010

У вас есть два варианта:

  1. Всегда передавать информацию в Logger
  2. Пусть Logger поддерживает его статически в Logger (или вызывает другой метод)

Если вы не хотите, чтобы Logger поддерживал его статически, и вы не хотите включать дополнительную информацию (или вызовы) в вызов каждый раз, тогда вы можете создать другой класс, который вызывает Logger и передает все эти статические затем измените Logger, чтобы он не имел статических данных (или, по крайней мере, не вызывал CurrentUser). Тогда класс, который вызывает logger, может принять CurrentUser в своем конструкторе.

Вы можете использовать это как трамплин для будущего рефакторинга.

Если ваш язык поддерживает методы расширения или помощники классов, вы можете изменить Logger так, чтобы он принимал CurrentUser в качестве параметра, а затем добавить метод расширения, который принимает только текст журнала, а затем автоматически передает CurrentUser. Это позволит вам внести изменения без изменения всех вызовов, хотя для этого потребуется, чтобы метод расширения был статическим. , , таким образом, вы не получаете много земли.

0 голосов
/ 22 февраля 2010

Одним из вариантов может быть создание нового интерфейса ContextProvider и получение оттуда вашей контекстной строки

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

Вы могли бы пойти дальше и использовать Formatter вместо contextProvider, за который будет отвечать форматер.взятие входной строки «текст» и ее полное форматирование, включая добавление любой сессии, даты, времени, запроса и т. д. информации.Вы можете посмотреть на log4 * для полной реализации этого.

В дополнение к этому я хотел бы предложить, чтобы перемещение метода log в метод экземпляра, а не статический метод было бы очень хорошим ходом, вы можете либо поддерживать оба на некоторое время со статическим помеченным как устаревшее, либодостань свою находку и замени палку.Одна из особенностей log4 *, которая мне действительно нравится, - это возможность изменять чувствительность регистрации в зависимости от класса или пакета.

0 голосов
/ 22 февраля 2010

У вас нет большого выбора здесь. Если вы не хотите, чтобы регистратор полагался на CurrentUser, вы можете рассчитывать на то, что конечный пользователь (класс журналирования) вставит пользователя в текст журнала или создаст подкласс регистратора, который знает о CurrentUser, что может победить свою цель.

...