Java记录与抽象类

时间:2012-08-28 13:41:08

标签: java inheritance logging abstract-class

我正在开发一个项目,目前正在使用log4j实现一些日志记录,我很好奇我应该如何实现日志。我正在讨论的两个实现如下:

第一个选项

为该类和所有子类使用来自超类的单个日志:

public abstract class AbstractFoo {
    protected static Log LOG = LogFactory.getLog(AbstractFoo.class);

    ...
}

public class Foo extends AbstractFoo {
    public void someMethod() {
        LOG.info("Using abstract log");
    }
}

第二个选项

为每个类使用单独的日志,super和subs:

public abstract class AbstractFoo {
    private static Log LOG = LogFactory.getLog(AbstractFoo.class);

    ...
}

public class Foo extends AbstractFoo {
    private static Log LOG = LogFactory.getLog(Foo.class);        

    public void someMethod() {
        LOG.info("Using own log");
    }
}

什么更有意义?为什么?

6 个答案:

答案 0 :(得分:82)

我也不愿意。相反,我会在两种情况下都使用正确的类。

public abstract class AbstractFoo {
    protected final Log log = LogFactory.getLog(getClass());

    ...
}

public class Foo extends AbstractFoo {
    public void someMethod() {
        log.info("Using abstract log");
    }
}

如果您没有进行大量的日志记录(无论如何这都是个好主意),您可以改用一种方法。

public abstract class AbstractFoo {
    protected Log log() { return LogFactory.getLog(getClass()); }

    ...
}

如果有一个类调用了很多,你可以覆盖它以给你一个缓存的实例。

答案 1 :(得分:10)

这是我的解决方案(最终静态记录器):

public abstract class AbstractFoo {
     protected abstract Log getLogger();
     public doSomething() {
          getLogger().info("log something");
     }
}

public class Foo extends AbstractFoo {
    private static final Log log = Log.getLogger(Foo.class);

    protected Log getLogger() {
         return log;
    }
    public doSomethingElse() {
          log.info("log somethingElse");
    }
}

答案 2 :(得分:4)

两者都有道理。这取决于您的应用程序。

我认为更常用的做法是为每个班级设置私人记录器。这允许您配置每个类和每个包的日志记录。请注意,AbstractFooFoo可能属于不同的软件包,您可能只希望查看来自Foo的日志。

此外,如果您想写protected字段,请务必三思而后行。它并非完全被禁止,而是众所周知的不良做法。它使您的代码可读性降低,难以维护。

答案 3 :(得分:1)

如果在抽象类中创建记录器,则日志将全部标记为源自AbstractFoo。如果您希望/需要查看使用发生日志的子类标记的日志,请为子类创建记录器。

答案 4 :(得分:1)

通过使用构造函数可以实现同样的目的。在 Base 类级别添加记录器,并使用super()从每个 Derived 类设置它。有代码:

public abstract class AbstractFoo {

    protected Log log;  // base abstract class has a Log object.

    public AbstractFoo(Log logger) {   // parameterized constructor for logger, to be used by the derived class.
        this.log = logger;
    }

    public doSomething() {        // common method for all the derived classes.
      log.info("log something");
    }
    // rest of business logic.
}

public class Foo extends AbstractFoo {

    public Foo(){
        super(LogFactory.getLog(AbstractFoo.class));
    }

    public void someMethod() {
        log.info("Using own log");     // this uses its own logger.
    }
}

答案 5 :(得分:0)

在抽象类中使用Logger有两个原因(我能想到):

  1. 在抽象类的方法中使用记录器,同时仍将 concrete 类作为调用者注销。
  2. 所有具体类之间的统一日志记录或通用日志记录。

如果您更喜欢静态记录器(这也是我的首选),那么n1cr4m的答案可以很好地解决#1和#2问题。

但是,如果您对#2更感兴趣并且不喜欢每个具体类都需要实现getLogger()的事实,那么您可以执行以下操作。作为示例,我将使用转换器:

public abstract class AbstractConverter{

   protected void logError(Logger logger, String someId, String msg){
       logger.error("Error during conversion of unit \""+ someId + "\": " + msg); 
   }

}

记录器可以是来自具体类的静态记录器。现在,无论何时登录,都将统一打印前缀,这也将强制标识其转换的对象。

此解决方案的缺点是,如果AbstractConverter需要自己使用记录器中的一种方法,它将无法使用具体类中的记录器,除非您也将其设为参数,我极力劝阻。如果您需要这种功能,请使用n1cr4m的解决方案。