2015-04-06 67 views
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 


    } 
+2

这是“不时髦”,正是因为,正如你发现的那样,它确实导致了“非常离奇的行为”。通常最好不要让这些东西是静态的,而是将它们传递到明确需要的地方(或者隐式地使用依赖注入)。当他们只是创建单例或者进行纯计算时,静态初始化器是很好的,但是它们通常不应该与文件系统,数据库或任何外部的任何事情交互。 –

+0

我在等人说这个。我得到了我欣赏的DI范例。但是,在我们准备扩大到DI驱动的框架之前,我有点希望保持我们有更长一段时间。 – tmn

+1

你不需要在这里使用DI,但是如果你能够完全实现这个功能,我会感到很惊讶,而且它会保持非常脆弱,难以测试,并且坦率地说,要花费更多的努力将采取。 –

回答

3

所以我想知道如果它是犹太使用静态初始化

有趣的是,

private static final boolean subscribed = subscribe(); 

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

GET编译到完全一样相同的字节码。所以使用不必要的静态变量是严格的更糟。


但是,直到我们准备扩展到一个DI驱动的框架,

发现Guice。不要称之为框架(尽管如此)。它很容易使用,让我们摆脱static

或者手动完成。通过删除所有静态修饰符并将其传递到需要的地方来重写您的类。它有时比较冗长,但明确声明依赖性可以让你独立地测试类。

它是这样的,无论测试方法多么微不足道,您都无法测试StratBand而无法击中数据库。问题是每个StratBand实例与所有StratBand的列表的耦合。因为它总是从数据库中加载(当然,你可以相应地填充你的数据库,但这是一个很大的麻烦),你不能测试依赖于stratBands内容的行为。对于初学者,我会创建StratBandManager(或StratBands或任何你喜欢的名称),并将所有静态功能移动到它。为了便于过渡,我想创建一个临时静态佣工像

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

然后弃用这一切,并通过DI(使用吉斯或做手工)替换它。


I find Guice即使对于小项目也很有用。经常没有或几乎没有任何配置,开销很小。

+0

是的,我花了很多时间学习Guice,虽然我还没有申请它,并希望。考虑到我们目前的商业环境和我们的功能,我们采取了极简主义的方法......而通过极简主义,我的意思是巩固和减少类的数量,如果它简化了事情。我肯定会需要考虑你的转换建议,因为社区似乎坚持解耦和使用DI。 – tmn

+0

@ThomasN。我不会尽量减少班级数量。您可能希望为“管理员”使用嵌套类,以便保持较低的文件数量,但其他类本质上是免费的(除了Android上可能存在的内存成本)。 – maaartinus

+0

是的,我一直喜欢嵌套类,因为它将所有内容保存在一个地方。我认识到当一定的复杂性阈值通过时它可能会导致应变可维护性。我想我会进一步发展我的方法,并开始更多地利用封装私有范例,以及接近DI友好型设计。 – tmn