6

当作为参数传递时,我可以使对象不可变,以便被调用的方法不能更改它但被调用者可以?

所以我有这样的事情:

Class Car {
  Wheel wheel_1;

  Axis axis = new Axis(wheel_1);
}


Class Wheel {
  int size;

  setSize(int size) {}
  int getSize() {}      
}

现在我建造了一辆带轮子的汽车。然后从类车我想构建一个轴。

为此,我将 wheel_1 传递给 Axis 的构造函数。

现在我的问题是:我能否以某种方式确保 Axis 的构造函数不会改变 wheel_1 的大小,但 class car 可以改变它。

4

6 回答 6

6

是的。通常这是通过使用类的复制构造函数来完成的Wheel

例如:

wheel_1 = new Wheel(wheel);

请记住,Wheel课程需要以支持这一点的方式编写。也就是说,它应该提供一个复制构造函数。

注意:这并没有使对象 immutable。它只是制作了一个副本,你的班级以外的任何人都无法编辑它。

如果您Wheel从任何其他方法返回实例,请务必在退出时防御性地复制它:

Wheel getWheel() {
  return new Wheel(wheel_1);
}

最后,值得一提的是,尽可能创建不可变类总是一个好主意。所以也许你可以通过实际制作不可变来避免这个问题Wheel

于 2013-04-19T09:37:45.573 回答
5

使Wheel类不可变。然后让对象在需要新大小时Car创建一个新对象。Wheel

public final class Wheel {
    private final int size;

    public Wheel(int size) {
        this.size = size;
    }

    public int getSize() {
        return size;
    }
}

现在您可以毫无问题地将轮子对象传递给 Axis。

public class Car {
    private Wheel wheel;
    private Axis axis;

    public Car(int initialWheelSize) {
        wheel = new Wheel(initialWheelSize);
        axis = new Axis(wheel);
    }
}
于 2013-04-19T09:47:38.527 回答
3

Axis向构造函数传递wheel_1.

class Car {
    Wheel wheel_1;

    Axis axis = new Axis(new Wheel(wheel_1));
}

此外,Wheel将需要一个构造函数来获取另一个Wheel对象并复制其属性。

于 2013-04-19T09:38:16.357 回答
2

为什么不将参数作为没有 setSize() 方法的超类发送

Class Car {
  Superwheel wheel_1;

  Axis axis = new Axis(wheel_1);
}

class Superwheel
{
   int size;
 int getSize() {}    
}

Class Wheel extends Superwheel{
  int size;

  setSize(int size) {}
  int getSize() {}      
}
于 2013-04-19T09:39:15.000 回答
2

我会让 Wheel 实现一个只有访问器方法的接口,即: -

例子

interface WheelInterface
{
  int getSize();
}

class Wheel implements WheelInterface
{
  // methods
}

class Axis
{
  public Axis(WheelInterface wheel)
  {
    // Only getSize will be available
  }
}

现在,只需传递 WheelInterface 而不是 Wheel 并且只有访问器方法可用于 Axis 类的构造函数

好处

这样做的好处是不需要复制;您只是向 Axis 类提供了一个合同,并且该合同声明它只能获取大小,而不能更改它。

通过按值传递相同的对象引用,您不必调用任何复制构造函数,也不必担心深浅复制语义。我不想在我的轮子上使用克隆,由于其他答案的评论中提到的原因,我认为这感觉有点脏。

在面向对象的模式中,使用接口抽象出你不需要的东西也是良好设计的标志。如果您的车轮上装有雪地轮胎,那么您的 Axis 课程可能甚至不需要关心!

缺点

正如其他人所提到的,可以将接口转换回具体类型(正如其他人所提到的,假设您知道要转换的内容);这称为向下转换,我不推荐它;如果这是在类似的情况下完成的,它可能无法通过代码审查

于 2013-04-19T09:44:00.443 回答
1

是的你可以。如果您将 Car 和 Wheel 放在同一个包中并声明 Wheel setter 字段受到保护。因此,如果在另一个包中声明 Axis,则无法访问 Wheel 的设置器,从而使 Wheel 从 Axis 的角度来看是不可变的。

好吧,这个解决方案是基本的开始。当然,你可以根据你想使不可变的级别来考虑是否使Wheel最终,克隆,可序列化等。

于 2013-04-19T09:39:22.900 回答