代码之家  ›  专栏  ›  技术社区  ›  Tom Tresansky

Java成员初始化模式

  •  3
  • Tom Tresansky  · 技术社区  · 14 年前

    我有一个班级我的班级:

    public class MyClass {
      private MyComplexType member1;
    }
    

    member1 MyClass 建造师。

    private MyComplexType initMyComplexType() { 
      MyComplexType result = new MyComplexType();  
      // extensive initialization on result...
      return result;
    }
    

    这样称呼:

    public MyClass() {
      member1 = initMember1();
    }
    

    或者

    private void initMember1() {
      member1 = new MyComplexType();
      // extensive initialization on member1...
    }
    

    这样称呼:

    public MyClass() {
      initMember1();
    }
    

    哪一种款式比较适合一位女士 成员?为什么?

    7 回复  |  直到 14 年前
        1
  •  6
  •   Péter Török    14 年前

    我会选择第一个选项,因为它更清楚地表达了init方法的目的,并显式地显示了数据流。

    更不用说它使init方法中的代码具有潜在的可重用性。如果以后需要初始化另一个变量,只需再次调用该方法,而不必担心副作用。此外,如果另一个变量在另一个类中,您可以很容易地将方法移动到两个地方都可以访问的地方。

    沿着这条路线,我还将考虑将init方法保留为 doExtensiveComplexCalculation 将其与实际成员变量解耦。

        2
  •  4
  •   Adriaan Koster    14 年前

    第二种方法的另一个缺点是,字段member1可能会将部分初始化的MyComplexType暴露给另一个线程。

    public class StaticOverrideParent {
    
     protected static void doSomething() {
      System.out.println("Parent doing something");
     }
    }
    
    public class StaticNoOverride extends StaticOverrideParent {
    
     public static void main(String[] args) {
      doSomething();
     }
    }
    
    public class StaticOverride extends StaticOverrideParent {
    
     protected static void doSomething() {
      System.out.println("Doing something");
     }
    
     public static void main(String[] args) {
      doSomething();
     }
    }
    

    运行StaticNoOverride会显示“家长在做什么”。

        3
  •  3
  •   Mark Peters    14 年前

    只有第一个允许你把结果分配给最后一个成员,这对我来说已经足够了。

        4
  •  3
  •   Konrad Garus    14 年前

    选择选项1。除了彼得提到的原因,这是一个更好的做法,因为这样你有一个 计算密集但无副作用 功能 init() ,和 . 将这两个特性分开是公认的良好实践。

    开放供扩展

    编辑:如其他人所说,也考虑重命名 initComplexMember() buildContextMember() .

        5
  •  2
  •   Pascal Thivent    14 年前

    坚强的 对我来说足够了。我将从Java教程中添加一些摘录:

    Initializing Instance Members

    通常,你会把代码 初始化实例中的实例变量 建造师。有两个 初始化实例变量: 初始化程序块和final方法。

    例如,初始化程序块 初始值设定项块,但没有 静态关键字:

    {
    
        // whatever code is needed for initialization goes here
    }
    

    Java编译器复制初始值设定项 因此,可以使用这种方法 多个构造函数。

    不能在中重写final方法 一个子类。这将在 下面是一个使用final 变量:

    class Whatever {
        private varType myVar = initializeInstanceVariable();
    
        protected final varType initializeInstanceVariable() {
    
            //initialization code goes here
        }
    }
    

    这是特别有用的,如果 子类可能希望重用 初始化方法。方法是 实例初始化期间的方法 会引起问题。约书亚·布洛克 在中对此进行了更详细的描述 Effective Java

    我倾向于使用上面的样式(除非我不希望初始化发生在所有构造函数中,但这是不寻常的)。

        6
  •  1
  •   Alan Krueger    14 年前

    我更喜欢 Spring IoC container 你所描述的那种复杂的硬编码初始化。它可以更好地分离关注点,并为单元测试提供更好的环境。

        7
  •  1
  •   Jörn Horstmann    14 年前

    静止的