如何将静态调用从类中分解出来

时间:2010-02-22 16:22:29

标签: language-agnostic refactoring static-methods

假设我有一个名为Logger.log()的静态方法,它调用另一个静态方法CurrentUser.getName()来获取一些其他信息来记录:

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

现在显然这不是一个理想的情况,特别是对于CurrentUser类中的静态数据。但我想通过减少Logger的依赖性来开始改进它。我更喜欢Logger不了解像用户这样的高级概念。它只需要记录的事项列表,而不关心它们是什么。

所以我想以某种方式分解出CurrentUser类。但Logger是静态的,所以我不能只将信息传递给它的构造函数。

将这样的事情分解出来会有什么好的模式?

5 个答案:

答案 0 :(得分:2)

在我看来,您的Logger已经保持某种状态(例如,日期,地址,用户等)。

将log()作为特定记录器上的非静态调用,并且在首次创建记录器时初始化所有相关内容(包括用户)是不是有意义?你可以使用一个记录器管理器来初始化并稍后获取特定的记录器,或者只是让你的记录器成为单例(如果是这样的话)。然后,获取用户的逻辑将在记录器的记录器管理器或工厂/ getInstance()中,而不是在Logger实例本身中。

答案 1 :(得分:1)

您有两种选择:

  1. 始终将信息传递给Logger
  2. 让Logger在Logger中静态维护(或调用其他方法)
  3. 如果您不希望Logger静态维护它,并且您不希望每次都在呼叫中包含其他信息(或调用),那么您可以创建另一个调用Logger并传递所有静态的类信息,然后将Logger更改为没有静态数据(或至少不调用CurrentUser)。然后调用logger的类可以在其构造函数中接受CurrentUser。

    您可以将其作为未来重构的垫脚石。

    如果您的语言支持扩展方法或类助手,则可以将Logger更改为接受CurrentUser作为参数,然后添加仅接受日志文本的扩展方法,然后自动传递CurrentUser。这将允许您在不更改所有调用的情况下进行更改,但这需要扩展方法是静态的。 。 。所以你没有多少收获。

答案 2 :(得分:1)

  

我更喜欢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);

答案 3 :(得分:0)

你这里没有很多选择。如果您不希望记录器依赖于CurrentUser,您可以依赖最终用户(日志记录类)将用户插入日志记录文本,或创建一个知道CurrentUser的记录器子类,打败你的目的。

答案 4 :(得分:0)

一个选项可能是创建一个新的接口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,格式化程序将负责获取输入字符串“text”并完全格式化,包括添加任何会话,日期,时间,请求等信息。您可以查看log4*以获取完整的信息。

在旁注中我建议将日志方法移动为实例方法而不是静态方法将是一个非常好的举动,你可以支持两次静态标记为已弃用,或者你可以得到你的找到并替换棒。我真正喜欢的log4 *的一个特性是能够根据类或包更改日志记录敏感度。