Java - 抽象类中的链接构造函数

标签 java constructor abstract-class

我正在进行模拟,我想基于 GenericMissile 抽象类创建一系列导弹类。我想确保所有常见的初始化都发生在 GenericMissile 中,这样我就可以避免将重复的代码传播到子类中。某些参数对于所有导弹都具有相同的值,因此这些参数位于通用导弹中。此外,大多数其他参数对于所有导弹来说都是通用的,只是具有不同的值。最后,有些导弹可能有也可能没有一些可选参数(它们可以以不同的排列存在,即使对于同一子类也是如此)。我的问题是如何正确链接抽象类中的构造函数以实现此行为。这是我正在尝试做的事情的模型:

public abstract class GenericMissile {
    public abstract void initSpecificParams();
    private double x;
    private double y;
    private double z;
    protected int optionalParam1 = 0;
    protected int optionalParam2 = 0;
    protected int optionalParam3 = 0;



public GenericMissile(double x, double y, double z) {  // basic constructor with required params
    this.x = x;
    this.y = y;
    this.z = z;
    initSpecificParams();  // each missile type initializes common params that needs specialized values
}

// --------------------------------
// OPTION 1:  duplicate everything from basic constructor, and add optional stuff
public GenericMissile(double x, double y, double z, int optionalParam1, int optionalParam2, int optionalParam3) {
    this.x = x;  // duplicating all these assignments
    this.y = y;
    this.z = z;
    this.optionalParam1 = decode(optionalParam1);  // using "decode" as a generic representation for doing unit conversion, scaling, enum-to-enum type mappings, etc.
    this.optionalParam2 = decode(optionalParam2);
    this.optionalParam3 = decode(optionalParam3);  
    initSpecificParams();
}
... // create one constructor like this for each combo of optional Params


// -------------------------------
// OPTION 2:  duplicate everything from basic constructor, and add optional stuff
public GenericMissile(doublex, double y, double z, int optionalParam1) {
     this(x,y,z);
     initSpecificParams(optionalParam1);
}
// ... (create a GenericMissile constructor with each permutation of optionalParams, that calls the appropriate initSpecificParams(...)

//------------------------------
// OPTION 3: try to re-use the first constructor (which is tricky because of the dependence of initSpecificParams() on the optional parameters being set 
public GenericMissile(double x, double y, double z, int optionalParam1, int optionalParam2, int optionalParam3) {  // When a missile type uses optional parameter, it uses this constructor instead
   this.optionalParam1 = optionalParam1;   // I know this is illegal, but this is what I would like to do, because initSpecificParams() will check for these optional parameter values
   this.optionalParam2 = optionalParam2;   
   this.optionalParam3 = optionalParam3;  
   this(x,y,z);  // not on the first line  :(
}

}

public class MissileA extends GenericMissile {
     public MissileA(double x) {
         super(x);
     }
     // Note: three constructors with optional params, all re-using the same GenericMissile constructor (good!), which in turn calls the sub-class implementation of initSpecificParams()
     public MissileA(double x, double y, double z, int optionalParam1) {
         super(x, y, z, optionalParam1, optionalParam2, optionalParam3);
     }

 public MissileA(double x, double y, double z, int optionalParam1, int optionalParam2) {
     super(x, y, z, optionalParam1, optionalParam2, optionalParam3);
 }

  public MissileA(double x, double y, double z, int optionalParam1, int optionalParam2, int optionalParam3) {
     super(x, y, z, optionalParam1, optionalParam2, optionalParam3);
 }

 // --------------------------
 // OPTION 1:
 // Ideally, I would be able to set any optional parameters in the Generic constructor, and then use the same initSpecificParams() method regardless of which 
 // optional parameters are being used - no duplication
 public void initSpecificParams() {
     if (optionalParam1 != 0 ) {
         readSpecificParameterFile1(optionalParam1);
     } else {
         readDefaultParameterFile();
     }
     if (optionalParam2 != 0 ) {
         readSpecificParameterFile2(optionalParam2);
     } else {
         readDefaultParameterFile();
     }
     if (optionalParam3 != 0) {
         readSpecificParameterFile3(optionalParam3);
     } else {
         readDefaultParameterFile();
     }

    do_common_stuff(); // NOTE: this common initialization depends on which parameter files are loaded in the previous if-else blocks
 }

 // -----------------------------
 // OPTION 2: include these extra initSpecificParams() methods
 // If I cannot set optional params in GenericMissile constructor in front of another constructor call, I have to build separate initSpecificParams() methods to explictly 
 // pass in the optional params, instead of just setting them as instance variable values -- lots of duplication in having to do that
 public void initSpecificParams(int optionalParam1) {
     this.optionalParam1 = optionalParam1; 
     initSpecificParams();  // NOTE: no way to force subclasses to chain these initialization methods properly

 }    

 // Significant duplication
 public void initSpecificParams(int optionalParam1, int optionalParam2) {
     this.optionalParam1 = optionalParam1; 
     this.optionalParam2 = optionalParam2; 
     initSpecificParams();  // NOTE: no way to force subclasses to chain these initialization methods properly
 }    


 // Significant duplication
 public void initSpecificParams(int optionalParam1, int optionalParam2, int optionalParam3) {
     this.optionalParam1 = optionalParam1; 
     this.optionalParam2 = optionalParam2; 
     this.optionalParam3 = optionalParam3; 
     initSpecificParams();  // NOTE: no way to force subclasses to chain these initialization methods properly
 }

}

看来我被迫:

  1. 复制两个 GenericMissile 构造函数中的所有代码(使用 第二个中的附加参数设置),或
  2. 在每个子类中复制 initSpecificParams() 方法并确保它们链接在一起(initSpecificParams(optional_param) 必须调用 initSpecificParams())。

是否有一些更干净的方法可以做到这一点,而我不必重复这么多代码?注意:我已经缩短了这个示例......实际上有大量的通用参数、具有不同值的公共(public)参数以及可选参数。这里有很多 SLOC。

最佳答案

在这种情况下,您可以简单地以其他方式链接构造函数:

public GenericMissile(double x) {
  this(x, "");
}

public GenericMissile(double x, String optionalParam) {
  this.x = x;
  this.optionalParam = optionalParam;
  initSpecificParams();
}

但一般来说,这种多步骤初始化是一种代码味道(正如 Jon Skeet 在评论中所说,你可能不应该从构造函数中进行虚拟方法调用)。

从你的例子中很难看出,但使用 composition instead of inheritance 可能会取得更好的成功。 ,也许通过应用 Strategy pattern .

关于Java - 抽象类中的链接构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33587912/

相关文章:

java - 使用带有提示和用户输入的扫描仪

Java 复制构造函数

c++ - 自定义类的正确构造函数

java - OO 设计 - 将结果的责任委托(delegate)给不同的类

c++ - 一个抽象类可以作为其他具体类的成员作为组合关系吗? C++

java - Android 按钮文本和 HTML 上标和下标

java - 使用 MappingJackson2JsonView 支持在 Spring REST 中返回 JSON 响应比 @ResponseBody 注释有什么优势?

c++ - 模板移动构造函数

字符串的 Java 集合排序方法不适用于区分大小写和特殊字符

c++ - 隐式和显式复制构造函数调用