关于不可变模式的一些问题

时间:2018-12-02 21:59:03

标签: java design-patterns

我对不变模式有一些疑问。首先要解决该问题,我们需要确保以下几点:

1)访问属性的实例方法不得更改实例变量。

2)确保不可变类的构造函数是唯一    实例变量的值已设置或修改。 我认为通过将incident变量作为最终变量,那么如果存在更改此变量的方法将失败,即使构造函数也将无法更改此变量,因此,如果我们需要考虑这两个语句,为什么呢?可以使用最终关键字??我知道我想念一些东西。

2 个答案:

答案 0 :(得分:2)

制作真正的不可变品有一件重要的事情。组件可能是可变的数据结构,例如java.util.Date。以这个简单的类为演示目的:

final class DateWrapper {
  private final Date date;
  public DateWrapper(Date date) {
    this.date = date;
  }
  public Date getDate() {
    return date;
  }
}

现在您可以编写以下代码:

DateWrapper dw = new DateWrapper(new Date());
dw.getDate().setYear(2020);

这将修改类date的对象dw的实例变量DateWrapper。因此,此类并非真正不变。

要解决此问题,您必须制作如下防御副本:

final class DateWrapper {
  private final Date date;
  public DateWrapper(Date date) {
    // It must not be possible to modify the date after construction.
    // So use a copy of the original object in class DateWrapper.
    this.date = new Date(date.getTime());
  }
  public Date getDate() {
    // It must not be possible to modify the date in DateWarapper
    // So return a copy.
    return new Date(date.getTime());
  }
}

因此,其他任何类都无法获得对DateWrapper内部的可变引用。

另一个规则是:使您的类成为最终类,否则子类可以充当不可变的类,从而打破了不可变性的约定。这是一个恶意子类的示例,仅当DateWrapper不是final时,该子类才有效:

class Date2Wrapper extends DateWrapper {
  final Date date2;
  public Date2Wrapper(Date date) {
    super(date);
    this.date2 = date;
  }
  public Date getDate() {
    return date2;
  }
}

答案 1 :(得分:1)

首先,所有设计模式均不限于Java。它们可以用不同的语言实现,具有不同的风格。并非所有语言都具有final,即使java从一开始就没有final。

但是考虑到java的严格情况,final不能确保不变性:

  • 在对象中,如果可以访问成员,则可以使用成员的方法来更改状态。
  • 最终应用于对象可确保变量指向同一对象,但不会施加任何限制来避免更改状态(ball.setColor(“ red”)可以在最终的ball上执行)
  • 不变性意味着变量应该与另一个对象重新分配

例如:

Ball ball = new Ball(); 
ball = ball.makeRed();

在这种情况下,球是另一个球对象(使球克隆球并更改颜色)。当我们在String对象上运行方法时,也会发生同样的情况,将创建一个新的String对象以反映更改并返回:

String ball = 'Blue Ball';
ball = ball.replace('Blue', 'Red');