从java构造函数调用实例方法是好还是坏的做法?

有几种不同的方法可以初始化复杂的对象(注入的依赖关系和注入成员的所需设置),这些都看起来很合理,但有各种各样的优点和缺点.我会举一个具体的例子:
final class MyClass {
  private final Dependency dependency;
  @Inject public MyClass(Dependency dependency) {
    this.dependency = dependency;
    dependency.addHandler(new Handler() {
      @Override void handle(int foo) { MyClass.this.doSomething(foo); }
    });
    doSomething(0);
  }
  private void doSomething(int foo) { dependency.doSomethingElse(foo+1); }
}

你可以看到,构造函数做了3件事情,包括调用一个实例方法.我被告知,从构造函数调用实例方法是不安全的,因为它规避了未初始化成员的编译器检查.即我可以在设置this.dependency之前调用doSomething(0),这将被编译但没有工作.什么是最好的方式来重构这个?

>使doSomething静态并显式传递依赖关系在我实际的情况下,我有三个实例方法和三个成员字段,它们都相互依赖,所以这似乎是很多额外的样板,使所有这三个静态.
>将addHandler和doSomething移动到@Inject public void init()方法中.与Guice一起使用将是透明的,它需要任何手动构造来确保调用init(),否则如果有人忘记,对象将不会完全正常.此外,这暴露了更多的API,这两个似乎都是坏主意.
>包装一个嵌套类以保持依赖关系,以确保其正常运行,而不会暴露其他API:

class DependencyManager {
  private final Dependency dependency;
  public DependecyManager(Dependency dependency) { ... }
  public doSomething(int foo) { ... }
}
@Inject public MyClass(Dependency dependency) {
  DependencyManager manager = new DependencyManager(dependency);
  manager.doSomething(0);
}

这将实例方法从所有构造函数中抽出,但是会生成一个额外的类,当我已经拥有内部和匿名类(例如处理程序)时,可能会变得混乱 – 当我尝试这一点时,被告知要将DependencyManager移动到单独的文件,这也是令人讨厌的,因为它现在是多个文件做一件事情.

那么处理这种情况的首选方式是什么?

解决方法

有效Java中的Josh Bloch建议使用静态工厂方法,尽管我找不到任何参数.然而,在 Java Concurrency in Practice年有一个类似的情况,专门用于防止从构造函数中泄漏引用.适用于这种情况,它看起来像:
final class MyClass {
  private final Dependency dependency;

  private MyClass(Dependency dependency) {
    this.dependency = dependency;
  }

  public static createInstance(Dependency dependency) {
    MyClass instance = new MyClass(dependency);
    dependency.addHandler(new Handler() {
      @Override void handle(int foo) { instance.doSomething(foo); }
    });
    instance.doSomething(0);
    return instance;
  }
  ...
}

但是,使用DI注释可能无法正常工作.

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...