English 中文(简体)
如何将类中的静态调用因数化
原标题:How to factor static call out of a class

请允许我说,我有一种静态的方法,即Logger.log(),即另一种静态方法,即User.getName(现值)获得一些额外信息,以便记录:

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

现在很明显,这不是一个理想的情况,特别是在CurrentUser类的静态数据中。但是,我想通过减少Logger的依赖关系来开始改进它。我希望Logger不需要了解用户等较高级别的概念。它只需要一个将要记录的东西列表,而且不关心它们是什么。

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

这类因式分解的好模式是什么?

问题回答

在我看来,您的记录器似乎已经维护了一些状态(例如日期、地址、用户等)。

把log()变成特定的logger上的非静态调用并且在logger第一次创建时初始化所有相关内容(包括用户),这不是很合理吗?你可以有一个logger管理器来初始化和获取指定的loggers,或者仅使你的logger成为一个单例(如果是这样的话)。获取用户的逻辑将在loggers管理器或logger的factory/getInstance()中,而不是Logger实例本身。

您有两个选择:

  1. Always pass the information to Logger
  2. Have Logger maintain it statically within Logger (or call another method)

如果您不想让Logger静态地维护它,并且您不想每次都在调用中包含附加信息(或调用),那么您可以创建另一个类来调用Logger并传递所有静态信息,然后将Logger更改为没有静态数据(或至少不调用CurrentUser)。然后调用Logger的类可以在其构造函数中接受CurrentUser。

你可以将其用作未来重构的一个抓手。

如果您的语言支持扩展方法或类助手,那么您可以更改Logger接受CurrentUser作为参数,然后添加一个仅接受日志文本的扩展方法,然后自动传递CurrentUser。这将允许您进行更改而不更改所有调用,尽管它需要扩展方法是静态的...所以您不会获得太多的优势。

I d prefer that the Logger not have any knowledge of higher-level concepts like users.

听起来你可能想要走的方向是将日志信息的组成逻辑和格式化逻辑与日志机制分离。例如(请谅解我的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);

你没有很多选择。如果你不想记录器依靠于CurrentUser,你可以依靠最终用户(日志类)将用户插入到日志文本中,或者创建一个知道CurrentUser的子类记录器,这可能会打败你的目的。

其中一个选项是创建一个新的接口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)
    }
}

你可以更进一步,使用格式化程序而不是上下文提供程序,格式化程序将负责获取输入字符串“text”并完成格式化,包括添加会话、日期、时间、请求等信息。您可以查看 log4* 来获得完整的实现。

在一份脚注中,我建议,将标识方法变成一种不是一种固定方法的典型方法,会是一种非常好的举动,你既可以支持一种,也可以支持静态的标志,或者你可以找到并替换标签。 我真正喜欢的标志4* 的一个特征是,能够根据类别或一揽子办法改变对伐木的敏感性。





相关问题
XML-RPC Standard and XML Data Type

I was looking at XML-RPC for a project. And correct me if I m wrong, but it seems like XML-RPC has no XML datatype. Are you supposed to pass as a string? or something else? Am I missing something? ...

Is it exists any "rss hosting" with API for creating feeds

I am creating a desktop app that will create some reports. I want to export these reports as RSS or ATOM feeds. I can easily create feeds with Rome lib for Java. But I have no idea how to spread them. ...

Improving Q-Learning

I am currently using Q-Learning to try to teach a bot how to move in a room filled with walls/obstacles. It must start in any place in the room and get to the goal state(this might be, to the tile ...

High-traffic, Highly-secure web API, what language? [closed]

If you were planning on building a high-traffic, very secure site what language would you use? For example, if you were planning on say building an authorize.net-scale site, that had to handle tons ...

Def, Void, Function?

Recently, I ve been learning different programming langages, and come across many different names to initalize a function construct. For instance, ruby and python use the def keyword, and php and ...

热门标签