java - 通过设置静态字段禁用一个静态方法调用的 if-Condition

标签 java coding-style static-methods static-members

我们有一个类,让它在我们的项目中命名为 AttributeUpdater,处理从一个实体到另一个实体的值复制。核心方法遍历实体的属性并将它们按指定复制到第二个实体中。在该循环期间,AttributeUpdater 收集所有报告,其中包含有关在复制过程中覆盖了哪些值的信息,并将其收集到一个很好的列表中以供最终记录。如果值被覆盖的旧实体从未保存到数据库中,则删除此列表,因为在这种情况下,您只会覆盖默认值和被认为多余的日志记录。在伪 Java 代码中:

public class AttributeUpdater {
  public static CopyResult updateAttributes(Entity source, Entity target, String[] attributes) {
    List<CopyReport> reports = new ArrayList<CopyReport>();
    for(String attribute : attributes) {
          reports.add(copy(source, target, attribute));
    }
    if(target.isNotPersisted()) {
      reports.clear();
    }
    return new CopyResult(reports);
  }
}

现在有人顿悟了,在一种情况下,即使实体尚未持久化,报告实际上也很重要。如果我可以向方法签名添加另一个参数,这就不是什么大问题,但由于类的实际结构和所需的重构量,这有点不可行。由于该方法是静态的,我想出的唯一其他解决方案是添加一个标志作为静态字段并在函数调用之前设置它。

public class AttributeUpdater {

  public static final ThreadLocal<Boolean> isDeletionEnabled = new ThreadLocal<Boolean> {
      @Override protected Boolean initialValue() {
             return Boolean.TRUE;
      }      

  public static Boolean getDeletionEnabled() { return isDeletionEnabled.get(); }
  public static void setDeletionEnabled(Boolean b) { isDeletionEnabled.set(b); }

  public static CopyResult updateAttributes(Entity source, Entity target, String[] attributes) {
    List<CopyReport> reports = new ArrayList<CopyReport>();
    for(String attribute : attributes) {
          reports.add(copy(source, target, attribute));
    }
    if(isDeletionEnabled.get() && target.isNotPersisted()) {
      reports.clear();
    }
    return new CopyResult(reports);
  }
}

ThreadLocal 是一个用于线程安全的容器。这个解决方案,虽然它完成了工作,但至少对我来说有一个主要缺点:对于假设报告已删除的所有其他方法,现在无法保证这些报告将按预期删除。再次折射不是一种选择。所以我想到了这个:

公共(public)类 AttributeUpdater {

  private static final ThreadLocal<Boolean> isDeletionEnabled = new ThreadLocal<Boolean> {
      @Override protected Boolean initialValue() {
             return Boolean.TRUE;
      }      

  public static Boolean getDeletionEnabled() { return isDeletionEnabled.get(); }
  public static void disableDeletionForNextCall() { isDeletionEnabled.set(Boolean.FALSE); }

  public static CopyResult updateAttributes(Entity source, Entity target, String[] attributes) {
    List<CopyReport> reports = new ArrayList<CopyReport>();
    for(String attribute : attributes) {
          reports.add(copy(source, target, attribute));
    }
    if(isDeletionEnabled.get() && target.isNotPersisted()) {
      reports.clear();
    }
    isDeletionEnabled.set(Boolean.TRUE);
    return new CopyResult(reports);
  }
}

这样我可以保证对于旧代码,该函数将始终像更改之前一样工作。这个解决方案的缺点是,特别是对于嵌套实体,我将经常访问 ThreadLocal-Container - 迭代其中一个意味着为每个嵌套元素调用 disableDeletionForNextCall() 。此外,由于该方法总体上被多次调用,因此存在有效的性能问题。

TL;DR:查看伪 Java 源代码。第一个是旧代码,第二个和第三个是允许删除禁用的不同尝试。不能将参数添加到方法签名中。

是否有可能确定哪种解决方案更好,或者这仅仅是一个哲学问题?还是有更好的解决方案来解决这个问题?

最佳答案

确定哪种解决方案在性能方面更好的明显方法是对其进行基准测试。由于这两种解决方案都至少为了读取而访问线程局部变量,所以我怀疑它们会有太大差异。你也许可以像这样组合它们:

if(!isDeletionEnabled.get())
  isDeletionEnabled.set(Boolean.TRUE);
else if (target.isNotPersisted())
  reports.clear();

在这种情况下,您将受益于第二种解决方案(保证重置标志)而无需进行不必要的写入。

我怀疑会有很大的实际差异。幸运的是,HotSpot JVM 会将线程局部变量编译成一些不错的 native 代码,这些代码可以在没有太多性能损失的情况下运行,尽管我在这方面没有实际经验。

关于java - 通过设置静态字段禁用一个静态方法调用的 if-Condition,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12240017/

相关文章:

Java:使用.txt文件将每行的特定索引分配给数组列表

java - Spark作业失败,因为它找不到hadoop core-site.xml

java - 以编程方式更改 BMP 文件

php - 为什么从 PHP 5.4 开始永久启用 "echo"短标签?

c++ - VS2010 中的链接器错误(解决方案和静态方法中有 2 个项目)

c++ - 命名空间 + 函数与类上的静态方法

java - 默认的Hibernate(5.2.5) session 级缓存查杀性能是多少?

android - 如何在android中按主题级联样式

coding-style - 行注释字符和实际注释开头之间的空格

java - 方法头中的 'static' 是什么意思?