初始化子类中不同类型的'final'字段



我的问题与这里发布的问题几乎完全相同:带有最终未初始化字段的抽象类,我喜欢这个解决方案。然而,我的问题有点复杂,因为抽象类有多个不同类型的最终字段。例如,我有四个int、两个int[]和两个double。强制子类初始化这些变量的最佳方式是什么?

我考虑过的选项:

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

第一个选项不是很优雅,而且似乎有点复杂,尤其是对于数组。第二个选项非常乏味,而第三个选项似乎我做得太过火了

有"正确"的方法吗?或者,如果没有,提出的三个选项中哪一个会是最优雅的?

我会选择第二个,"拥有一个非常长的超类构造函数。"如果我们遵循您提到的问题中详细介绍的方法,超类构造函数是protected,不意味着由类层次结构或包外部的任何东西调用。我的感觉一直是,一旦某个东西没有超出这个界限——也就是说,它不是"API"的一部分——那么它看起来是什么样子就无关紧要了。让它有八个不同类型的参数,甚至更多。是的,它在包中是可见的,但从原始解决方案中可以清楚地看出,该构造函数不应该由子类以外的任何东西调用。这是非public可见性的另一个动机。

当然,当涉及到public的东西时,你做一些更清洁的事情的本能是正确的。你问这个问题说明你有正确的直觉。

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

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

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

是的,它会涉及一些代码复制,但最终它可能会比一个无法读取的长构造函数更干净,而且你复制的代码并不多——一个字段,一个返回该字段的单行方法。

然而,我的问题有点复杂,因为抽象类具有多个不同类型的最终字段。

我不确定我是否理解您的场景中增加的复杂性,但我将您的问题解释为:我不想在我的抽象构造函数上有太多争论。一种可能的方法是为具体子类使用的抽象类提供一个Builder。然后,生成器被"传递"到抽象构造函数,用于设置最终字段。

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

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

例如,您可以看到不可变集合生成器的Guava API。或者,如果您不需要不变性,这里有一个同样来自同一库的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),因为这将避免维护一个很长的构造函数的一些麻烦

最新更新