使用传递给构造函数的引用是否可行且安全 - Java

时间:2016-07-29 16:35:20

标签: java reference encapsulation

我已获得以下代码:

public class Triangle {

    private Point left;
    private Point right;
    private Point top;

    public Triangle(Point left, Point right, Point top) {
        this.left = left;
        this.right = right;
        this.top = top;
    }

    // more program logic...
}

我想知道构建这样的对象是否可行且安全,因为我担心Point类型的三个变量中的一些可以从外部修改(break encapsulation)。 例如:

public static void main(String[] args) {

    Point left = new Point(0.0, 1.0);
    Point right = new Point(2.4, 3.2);
    Point top = new Point(5.8, 2.0);

    Triangle t = new Triangle(left, right, top);

    top.setX(10.2);
    top.setY(23.4); 
}

毫无疑问,这将操纵同样的"顶部"在Triangle变量中引用的对象。 因此修复在Triangle构造函数中执行以下操作:

public Triangle(Point left, Point right, Point top) {
    this.left = new Point(left);
    this.right = new Point(right);
    this.top = new Point(top);
}

(请记住我在Point类中有一个复制构造函数,所以上面的三个语句都是有效的)

3 个答案:

答案 0 :(得分:4)

您可以克隆构造函数中的原始点,并使克隆与外界保持隐藏。如果Point已经实现了Cloneable,或者您可以自己实现它,请以这种方式使用它:

public Triangle(Point left, Point right, Point top) {
    this.left = left.clone();
    this.right = right.clone();
    this.top = top.clone();
}

如果Point没有实现Cloneable并且您无法访问其源代码,则只需手动克隆点:

public Triangle(Point left, Point right, Point top) {
    this.left = new Point(left.getX(), left.getY());
    this.right = new Point(right.getX(), right.getY());
    this.top = new Point(top.getX(), top.getY());
}

答案 1 :(得分:3)

这是一个非常好的问题。

具有可变状态并不总是坏事。例如,您可以将此Triangle对象实例发送到显示程序,如果您更改了点坐标,则可以在屏幕上为三角形设置动画。

它取决于用例以及它应该解决的问题。

如果你下定决心,对于你的用例,整个对象图(这个对象,我的孩子和孩子的孩子等)一旦创建就应该是不可变的,有办法确保。

为了使不可变对象真正不可变,这里有一些很好的指导: http://www.javapractices.com/topic/TopicAction.do?Id=29

如果对象具有集合作为属性,则可以根据需要使用Immutable或Unmodifiable集合: Java Immutable Collections

最后,如果您确实允许可变状态,并且想要跟踪,则可以将子对象注册为观察者。 When should we use Observer and Observable

同样,原则是保持尽可能少的可变状态。换句话说,始终尽可能保持对象不变。不可变的集合很容易获得并且易于使用。问题出在我们的自定义类上。

如果您使自定义对象/模型对象完全不可变,则可能会出现复制整个对象图以更改单个属性的情况。

所以,保守一点。特别是收藏品,很容易做到。

使用面向对象的编程范例很难避免可变性。功能编程应该与不变性更加一致。你可能想看看Haskell或Scala只是为了尝试。

https://softwareengineering.stackexchange.com/questions/232711/complete-immutability-and-object-oriented-programming

答案 2 :(得分:1)

如果你有一个复制构造函数,那么使用它是安全的。否则,如果点实现cloneable,则可以使用clone。