初始化子类中不同类型的“最终”字段

时间:2012-02-26 01:12:45

标签: java oop inheritance

我的问题与此处发布的问题几乎完全相同:Abstract class with final uninitialized field我喜欢这个解决方案。但是,我的问题有点复杂,因为抽象类有多个不同类型的最终字段。例如,我有四个int,两个int[]和两个double。强制子类初始化这些变量的最佳方法是什么?

我考虑的选项:

  • 将所有字段转换为字符串并使用Map
  • 传递
  • 有一个非常长的超类构造函数
  • 创建一个辅助类,它将充当包装器并封装所有值,然后将此类的实例传递给基类

第一个选项不是很优雅,看起来有点复杂,特别是对于数组。第二种选择非常繁琐,第三种选择似乎只是我过度了。

是否有正确的"这样做的方式?或者如果没有,提出的三个选项中哪一个最优雅?

4 个答案:

答案 0 :(得分:5)

我会选择第二个,“有一个非常长的超类构造函数。”如果我们遵循question you referenced中详述的方法,则超类构造函数为protected,并不打算由类层次结构或包外部的任何内容调用。我的感觉总是,一旦某些东西没有暴露在那个边界之外 - 也就是说,它不是“API”的一部分 - 那么它看起来并不重要。让它有八种不同类型的不同参数,甚至更多。是的,它可以从包中看到,但从原始解决方案中可以清楚地看出,该构造函数不应由除子类之外的任何东西调用。这是非public可见度的另一个动机。

当然,当谈到public时,你做干净事情的直觉是正确的。你问这个问题的事实表明你有正确的直觉。

答案 1 :(得分:2)

这是另一种选择,假设您可以控制所涉及的所有类:抽象出超类中的字段并在子类中声明它们,就像这样......

abstract class SuperClass {
  abstract int[] getFooArray(); // not public!
  abstract int getBar();
}

然后只需在每个子类中定义字段,覆盖返回它们的方法。

是的,它会涉及一些代码重复,但它最终可能比一个不可读的长构造函数更清晰,并且你复制的代码不是很多 - 一个字段,一行方法返回那个领域。

答案 2 :(得分:1)

  

然而,我的问题在摘要中有点复杂   class有多个不同类型的final字段。

我不确定我是否了解您的场景中增加的复杂性,但我将您的问题解释为:我不想在我的抽象构造函数上有大量的参数。一种可能的方法是为具体子类使用的抽象类设置Builder。然后将构建器“传递”到抽象构造函数以设置最终字段。

答案 3 :(得分:0)

当我需要一个不可变对象(所有成员都是最终成员)时,它在构造函数中采用了许多不同的参数,我通常使用Builder模式。

在这种情况下,您可以使构建器彼此子类化,这样您仍然可以保持扩展的能力。

有关示例,您可以看到Guutable API for ImmutableCollection Builder。 或者,如果您不需要不变性,这里有一个CacheBuilder的例子也来自同一个库:

Cache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .concurrencyLevel(4)
   .weakKeys()
   .maximumSize(10000)
   .expireAfterWrite(10, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) throws AnyException {
           return createExpensiveGraph(key);
         }
       });

正如您所看到的,使用构建器取代了在构造函数中传递6个参数的需要,并使代码更具可读性/可用性。

如果您仍然不想使用构建器,我会使用选项(3),因为这样可以防止维护非常长的构造函数的麻烦