作为参数传递时,使对象不可变

时间:2013-04-19 09:34:03

标签: java

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

所以我有这样的事情:

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的大小,但是类车可以改变它。

6 个答案:

答案 0 :(得分:5)

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

public final class Wheel {
    private final int size;

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

    public int getSize() {
        return size;
    }
}

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

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

    public Car(int initialWheelSize) {
        wheel = new Wheel(initialWheelSize);
        axis = new Axis(wheel);
    }
}

答案 1 :(得分:4)

是。通常,这是通过对Wheel类使用copy-constructor来完成的。

例如:

wheel_1 = new Wheel(wheel);

请记住,Wheel类需要以支持此类的方式编写。也就是说,它应该提供一个拷贝构造函数。

注意:这并没有使对象不可变。它只是制作了一个副本,不能被你班级以外的任何东西编辑。

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

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

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

答案 2 :(得分:3)

Axis构造函数传递给wheel_1

class Car {
    Wheel wheel_1;

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

此外,Wheel将需要一个构造函数,该构造函数接受另一个Wheel对象并复制其属性。

答案 3 :(得分: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() {}      
}

答案 4 :(得分: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级别可能甚至不需要关心!

<强>缺点

正如其他人所提到的,可以将界面强制转换为具体类型(正如其他人提到的那样,假设你知道你要投射的是什么);这被称为向下转换,我不推荐它;如果这是在类似的情况下完成的,它可能不会通过代码审查

答案 5 :(得分:1)

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

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