6

我记得几年前我使用静态初始化器来调用类级别的设置操作。我记得它有非常奇怪的行为,我只是决定避开它们。也许是因为我搞乱了上下顺序或者是新手。但是我遇到了重新审视它们的需要,并且我想确保没有更好的方法同样简洁。

我知道这并不流行,但我经常使用数据驱动的类来维护从数据库导入的实例的静态列表。

public class StratBand { 
      private static volatile ImmutableList<StratBand> stratBands = importFromDb();

      private final int minRange;
      private final int maxRange;

      private static ImmutableList<StratBand> importFromDb() { 
            //construct list from database here
      }
      //constructors, methods, etc
}

当我有几十个像这样的表驱动类时,这种模式非常简洁(是的,我知道它将类与一个数据/实例源紧密耦合)。

但是,当我发现 Google Guava 的优点时,我想在某个事件发布时使用 EventBus 更新静态列表。我将创建一个静态最终布尔变量,只是为了调用一个初始化注册的静态方法。

public class StratBand { 
      private static volatile ImmutableList<StratBand> stratBands = importFromDb();
      private static final boolean subscribed = subscribe();

      private final int minRange;
      private final int maxRange;

      private static ImmutableList<StratBand> importFromDb() { 
            //construct list from database here
      }
      //constructors, methods, etc

      private static boolean subscribe() {
            MyEventBus.get().register(new Object() { 
                @Subscribe
                public void refresh(ParameterRefreshEvent e) { 
                    stratBands = importFromDb();
                }
            });
        return true;
      }
}

这很快就变得很烦人,因为编译器会对从未使用过的订阅变量发出警告。此外,它只是增加了混乱。所以我想知道使用静态初始化器是否符合规定,如果我不将它解耦成两个或更多类,真的没有更好的方法。想法?

 public class StratBand { 
          private static volatile ImmutableList<StratBand> stratBands = importFromDb();

          static { 
           MyEventBus.get().register(new Object() { 
                    @Subscribe
                    public void refresh(ParameterRefreshEvent e) { 
                        stratBands = importFromDb();
                    }
                });
          }

          private final int minRange;
          private final int maxRange;

          private static ImmutableList<StratBand> importFromDb() { 
                //construct list from database here
          }
          //constructors, methods, etc


    }
4

1 回答 1

3

所以我想知道使用静态初始化器是否符合规定

有趣的是

private static final boolean subscribed = subscribe();

private static final boolean subscribed;
static {
    subscribed = subscribe();
}

被编译成完全相同的字节码。所以使用不必要的静态变量严格来说更糟。


但在我们准备好扩展到一个 DI 驱动的框架之前,

发现Guice。不要称它为框架(尽管它是)。它易于使用,让您摆脱static.

或者手动进行。通过删除所有静态修饰符来重写您的类,并将其传递到您需要的任何地方。有时它相当冗长,但明确地说明依赖关系允许您单独测试类。

就这样,你无法StratBand在不访问数据库的情况下进行测试,无论被测试的方法多么微不足道。问题是每个StratBand实例与所有StratBands 的列表的耦合。

此外,您无法测试依赖于stratBands内容的行为,因为它总是从数据库加载(当然,您可以相应地填充您的数据库,但这是一个很大的痛苦)。

对于初学者,我会创建StratBandManager(或StratBands您喜欢的任何名称)并将所有静态功能移至它。为了便于过渡,我会创建一个带有静态助手的临时类,例如

private static StratBandManager stratBandManager = new StratBandManager();
public static ImmutableList<StratBand> stratBands() {
   return stratBandManager.stratBands();
}

然后弃用它并用 DI 替换它(使用 Guice 或手动执行)。


我发现Guice 即使对小型项目也很有用。开销很小,因为通常没有或几乎没有任何配置。

于 2015-04-07T00:28:22.753 回答