我有一个类,它定义了给定屏幕的所有基本参数。从这里,应用程序中的每个屏幕都是此类的子类。我需要每个屏幕(即子类)在其实现中设置变量的值(即,每个屏幕必须定义它在导航树中的级别)。
另外,理想情况下,当这个变量在子类中设置时,它应该是final
(我意识到这可能是不可能的)。
最好的方法是什么?有没有办法在Java中正确实施这种行为?
答案 0 :(得分:30)
@ pst的评论导致了这个解决方案。
使用变量无法做到这一点。但是抽象类可以要求实现特定方法:此方法可以返回适用的值
从声明abstract
函数设置或返回变量,您可以强制任何子类正确实现它。
接下来,该函数必须由外部类的每个子类调用。这意味着它必须在外部类中的某个地方完成。这可以在外部类的无参数构造函数中完成,而不必担心调用super
的子类:
注意:如果构造函数没有显式调用超类构造函数,Java编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,则会出现编译时错误。对象确实有这样的构造函数,因此如果Object是唯一的超类,则没有问题。 (Java docs: Super)
基于此,此解决方案将保持并正确强制要设置的变量,只要:
代码:
<强>超类:强>
public abstract class SuperClass {
// Variable all inner classes must set
static int myVar = 0;
public SuperClass() {
myVar = giveValue();
}
public abstract int giveValue();
}
<强>子类:强>
public class SubClass extends SuperClass {
@Override
public int giveValue() {
return 5; // individual value for the subclass
}
}
答案 1 :(得分:11)
您可以通过让父类构造函数采用实现提供您希望初始化的字段的接口的参数来遵循组合策略,而不是强制执行子类实例初始化字段。
class Screen {
final Configuration config;
Screen(Configuration config) {
this.config = config;
}
// or
Screen(ConfigFactory configFactory) {
this.config = configFactory.make();
}
}
interface ConfigFactory {
Configuration make();
}
我要警告不要求使用抽象方法实现初始化配置的子类实例。父类构造函数中的赋值发生在初始化子类实例之前,隐式正确地计算配置静态。
如果计算不是静态的,那么开发人员跟随你(或者如果你的记忆不够完美)就会冒着空引用或NullPointerExceptions的风险。让协作者(和您自己)更容易,并明确约束。
答案 2 :(得分:1)
正如@Ketan在@B T的答案中提到的那样,从构造函数中调用可重写的方法并不是特别好的做法(https://help.semmle.com/wiki/display/JAVA/Non-final+method+invocation+in+constructor)
避免此问题的一种方法是在该字段中使用抽象(受保护的)getter。因此,超类不再具有该字段,但仍可以使用getter在超类中对其进行访问。每个子类都必须声明该字段,因为它必须覆盖抽象的getter。
超类:
import { FileUploadI, GraphQLUpload } from 'graphql-upload'
@Mutation(() => Picture)
async uploadPicture(@Arg('data', () => GraphQLUpload) data: FileUploadI): Promise<Picture> {
//.. implementation
}
Subclass1:
public abstract class SuperClass {
public SuperClass() {}
protected abstract int getMyVar();
public void functionUsingMyVar(){
int a = 12 + getMyVar();
}
}
子类别2:
public class SubClass1 {
private int myVar;
public SubClass1() {
super();
myVar = 1;
}
@Override
protected int getMyVar(){
return myVar;
}
}
而不是拥有超类(在其中,GiveValue()是可重写的,并在构造方法中调用):
public class SubClass2 {
private int myVar;
public SubClass2() {
super();
myVar = 1;
}
@Override
protected int getMyVar(){
return myVar;
}
}