如何计算从辅助构造函数传递到主构造函数的值?

时间:2016-01-06 10:10:03

标签: scala constructor

我想定义一个辅助构造函数,它应该计算一些值并在传递给主构造函数的多个参数中使用它。表达这一点的一种自然方式是在调用主构造函数之前定义局部值,但语言不允许这样做:

public class MainActivity extends AppCompatActivity {

    RelativeLayout container;
    int cellWidth = 0, cellHeight = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
        tableLayout.setStretchAllColumns(true);
        for (int i = 0; i < 4; i++) {
            TableRow tableRow = new TableRow(this);
            for (int j = 0; j < 10; j++) {
                LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View cell = layoutInflater.inflate(R.layout.table_cell, null, false);
                if (cellHeight == 0 ) {
                    cell.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
                    cellWidth = cell.getMeasuredWidth();
                    cellHeight = cell.getMeasuredHeight();
                }

                tableRow.addView(cell);
            }

            tableLayout.addView(tableRow);
        }

        container = (RelativeLayout)findViewById(R.id.container);
        overlappingImage = new ImageView(this);
        overlappingImage.setScaleType(ImageView.ScaleType.FIT_XY);
    }

    ImageView overlappingImage;

    private void restoreTableLayout() {
        container.removeView(overlappingImage);
    }

    public void onClick11(View view) {
        restoreTableLayout();
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth, cellHeight);
        overlappingImage.setLayoutParams(params);
        overlappingImage.setImageResource(R.drawable.horizontal_cat);
        container.addView(overlappingImage);
    }

    public void onClick41(View view) {
        restoreTableLayout();
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth*4, cellHeight);
        overlappingImage.setLayoutParams(params);
        overlappingImage.setImageResource(R.drawable.horizontal_cat);
        container.addView(overlappingImage);
    }

    public void onClick32(View view) {
        restoreTableLayout();
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth*3, cellHeight*2);
        params.setMargins(cellWidth*2, cellHeight*2, 0 ,0);
        overlappingImage.setLayoutParams(params);
        overlappingImage.setImageResource(R.drawable.vertical_cat);
        container.addView(overlappingImage);
    }

    public void onClick22(View view) {
        restoreTableLayout();
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth*2, cellHeight*2);
        overlappingImage.setLayoutParams(params);
        overlappingImage.setImageResource(R.drawable.horizontal_cat);
        container.addView(overlappingImage);
    }
}

另一种方法是重复计算,但是由于计算非常复杂,这可能是一个问题(并且还会导致代码重复):

object Computed {
  def veryComplexComputation(x: Double) = math.sqrt(x) // imagine there is some much more complex computation here
}
class Computed(x: Double, y: Double, z: Double) {
  def this(x: Double, y: Double) = {
    val derivedFromX = Computed.veryComplexComputation(x)
    val derivedFromY = derivedFromX * Computed.veryComplexComputation(y)
    this(x, derivedFromX, derivedFromY)
  }
}

4 个答案:

答案 0 :(得分:2)

我知道的最好的技巧是使用第三个​​,私有构造函数,为主构造函数提供参数元组,以及随播对象中的辅助函数:

object Computed {
  def veryComplexComputation(x: Double) = math.sqrt(x) // imagine there is some much more complex computation here

  private def computeArgs(x: Double, y: Double): (Double, Double, Double) = {
    val derivedFromX = veryComplexComputation(x)
    val derivedFromY = derivedFromX * veryComplexComputation(y)
    (x, derivedFromX, derivedFromY)
  }
}

class Computed(x: Double, y: Double, z: Double) {
  private def this(xyz: (Double, Double, Double)) =
    this(xyz._1, xyz._2, xyz._3)

  def this(x: Double, y: Double) =
    this(Computed.computeArgs(x, y))
}

答案 1 :(得分:2)

我认为最好的方法是向配套对象添加合适的工厂方法:

object Computed {
  def veryComplexComputation(x: Double) = math.sqrt(x) // can be private, if you wish

  def apply(x: Double, y: Double): Computed = {
    val derivedFromX = veryComplexComputation(x)
    val derivedFromY = derivedFromX * veryComplexComputation(y)
    new Computed(x, derivedFromX, derivedFromY)
  }
}

然后你可以用与案例类相同的方式实例化你的Computed类型,然后使用&#34; new&#34;:

scala> val comp = Computed(4.0, 9.0)
comp: Computed = Computed@4de4e24f

(您可能还想考虑将Computed作为案例类 - 特别是如果完全或甚至大部分用作数据容器的话

答案 2 :(得分:0)

可以(ab)使用具有默认值的多个参数列表,如下所示:

class Computed(x: Double, y: Double, z: Double) {
  def this(x: Double, y: Double) = {
    this(
      x,
      Computed.veryComplexComputation(x),
      Computed.veryComplexComputation(x) * Computed.veryComplexComputation(y)
    )
  }
}

这利用了每个参数列表可以访问先前列表中的参数的事实。只是不要忘记在调用构造函数时提供空参数列表:

class Computed(x: Double, y: Double, z: Double) {
  def this(x: Double, y: Double)(
    derivedFromX: Double = Computed.veryComplexComputation(x)
  )(
    derivedFromY: Double = derivedFromX * Computed.veryComplexComputation(y)
  ) = {
    this(x, derivedFromX, derivedFromY)
  }
}

答案 3 :(得分:0)

可以链接几个辅助构造函数,每个辅助构造函数执行一次计算,使用标记特征来区分构造函数,以避免模糊性过载。

object Computed {
  def veryComplexComputation(x: Double) = math.sqrt(x) // imagine there is some much more complex computation here

  private trait DerivedFromX
  private object DerivedFromX extends DerivedFromX
}

class Computed(x: Double, y: Double, z: Double) {
  private def this(name: Computed.DerivedFromX, x: Double, derivedFromX: Double, y: Double) = {
    this(x, derivedFromX, derivedFromX * Computed.veryComplexComputation(y))
  }
  def this(x: Double, y: Double) = this(Computed.DerivedFromX, x, Computed.veryComplexComputation(x), y)
}