Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 初始化';最终';子类中不同类型的字段_Java_Oop_Inheritance - Fatal编程技术网

Java 初始化';最终';子类中不同类型的字段

Java 初始化';最终';子类中不同类型的字段,java,oop,inheritance,Java,Oop,Inheritance,我的问题几乎和这里贴的问题完全一样:我喜欢这个解决方案。然而,我的问题有点复杂,因为抽象类有多个不同类型的final字段。例如,我有四个int,两个int[],两个double。强制子类初始化这些变量的最佳方法是什么 我考虑过的选择: 将所有字段转换为字符串,并使用映射传递 有一个很长的超类构造函数 创建一个充当包装器并封装所有值的帮助器类,然后将该类的实例传递给基类 第一个选项不是很优雅,而且似乎有点复杂,特别是对于数组。第二种选择非常乏味,而第三种选择似乎我做得太过分了 有没有一种“正确

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

我考虑过的选择:

  • 将所有字段转换为字符串,并使用
    映射传递
  • 有一个很长的超类构造函数
  • 创建一个充当包装器并封装所有值的帮助器类,然后将该类的实例传递给基类
第一个选项不是很优雅,而且似乎有点复杂,特别是对于数组。第二种选择非常乏味,而第三种选择似乎我做得太过分了

有没有一种“正确”的方法?或者,如果不是,三个选项中哪一个是最优雅的

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


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

我将使用第二个“拥有一个非常长的超类构造函数”。如果我们遵循,超类构造函数受
保护
,不意味着被类层次结构或包外部的任何东西调用。我的感觉一直是,一旦某个东西没有超出这个界限暴露出来——也就是说,它不是“API”的一部分——那么它看起来像什么就不重要了。让它有八个不同类型的参数,甚至更多。是的,它在包中是可见的,但是从原始解决方案中可以清楚地看到,除了子类之外,该构造函数不应该被任何其他对象调用。这是非公开
可见性的另一个动机


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

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

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

例如,您可以看到用于ImmutableCollection的GuavaAPI。 或者,如果您不需要不变性,下面是一个同样取自同一库的示例:

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);
         }
       });
Cache graphs=CacheBuilder.newBuilder()
.1级(4)
.weakKeys()
.最大尺寸(10000)
.expireAfterWrite(10,时间单位:分钟)
.建造(
新缓存加载程序(){
公共图加载(键)引发任何异常{
返回createExpensiveGraph(键);
}
});
正如您所看到的,使用构建器取代了在构造函数中传递6个参数的需要,并使代码更具可读性/可用性


如果你仍然不想使用构造器,我会选择选项(3),因为这将避免维护一个很长的构造器的麻烦,这里还有另一个选择,假设你可以控制所有涉及的类:抽象出超类中的字段并在子类中声明它们,有点像这样

abstract class SuperClass {
  abstract int[] getFooArray(); // not public!
  abstract int getBar();
}
然后在每个子类中定义字段,重写返回它们的方法


是的,它会涉及一些代码复制,但最终可能会比一个难以理解的长构造函数更干净,而且您复制的代码不是很多——一个字段,一个返回该字段的单行方法。

这很有意义。这使得控制子类中的值变得非常容易,并使子类的构造保持简单。谢谢很乐意帮忙。总的来说,我的建议是:保持公共物品的高标准(优雅、图案等),不要害怕在私人/受保护的领域偷工减料。