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



我们有一个类,在我们处理从一个实体到另一个实体的值复制的项目中,将其命名为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是一个用于线程安全的容器。这种解决方案在起作用的同时,至少对我来说有一个主要缺点:对于所有其他假设报告已删除的方法,现在无法保证这些报告将按预期删除。再次强调,折射不是一种选择。所以我想出了这个:

公共类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);
  }
}

通过这种方式,我可以保证对于旧代码,函数将始终像更改前一样工作。这个解决方案的缺点是,尤其是对于嵌套实体,我将大量访问ThreadLocalContainer——对其中一个进行迭代意味着对每个嵌套元素调用disableDeletitionForNextCall()。此外,由于该方法总体上被调用了很多,因此存在有效的性能问题。

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

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

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

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

在这种情况下,您将获得第二种解决方案(保证重置标志)的好处,而不会出现不必要的写入。

我怀疑会有多大的实际差异。如果运气好的话,HotSpot JVM会将线程本地变量编译成一些不错的本地代码,虽然我在这方面没有实际经验,但它不会带来太多的性能损失。

最新更新