簡體   English   中英

Java-抽象類中的鏈構造函數

[英]Java - Chaining Constructors in Abstract Class

我正在進行一個仿真,我想基於GenericMissile抽象類創建一系列導彈類。 我想確保所有通用初始化都發生在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())。

在不必重復太多代碼的情況下,是否有一些更簡潔的方法來執行此操作? 注意:我已經簡化了這個示例……實際上,存在大量的通用參數,具有不同值的通用參數以及可選參數。 這里有很多SLOC。

在這種情況下,您可以簡單地以其他方式鏈接構造函數:

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

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

但是通常這種多步初始化是一種代碼味道(正如Jon Skeet在評論中所說,您可能無論如何都不應該從構造函數中進行虛擬方法調用)。

從您的示例很難看出來,但是通過使用合成而不是繼承 (也許通過應用Strategy模式)可能會獲得更好的成功。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM