Java中的不可变bean

Fra*_*ens 5 concurrency immutability javabeans

我非常好奇为java bean提供不变性的可能性(这里的bean我指的是带有空构造函数的类,为成员提供getter和setter).显然,这些类不是不可变的,并且它们用于从数据层传输值,这似乎是一个真正的问题.

StackOverflow中已经提到了一种解决这个问题的方法,称为"C#中的不可变对象模式",其中对象在完全构建后被冻结.我有另一种方法,并且非常希望听到人们对此的看法.

该模式涉及两个类Immutable和Mutable,其中Mutable和Immutable都实现了一个提供非变异bean方法的接口.

例如

public interface DateBean {
    public Date getDate();
    public DateBean getImmutableInstance();
    public DateBean getMutableInstance();
}

public class ImmutableDate implements DateBean {
    private Date date;

ImmutableDate(Date date) {
    this.date = new Date(date.getTime());
}

public Date getDate() {
    return new Date(date.getTime());
}

    public DateBean getImmutableInstance() {
        return this;
    }

    public DateBean getMutableInstance() {
        MutableDate dateBean = new MutableDate();
        dateBean.setDate(getDate());
        return dateBean;
    }
}

public class MutableDate implements DateBean {
    private Date date;

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

public DateBean getImmutableInstance() {
    return new ImmutableDate(this.date);
}

    public DateBean getMutableInstance() {
        MutableDate dateBean = new MutableDate();
        dateBean.setDate(getDate());
        return dateBean;
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法允许使用反射(按照惯例)构造bean,并允许我们在最近的机会转换为不可变的变量.不幸的是,每个bean显然有大量的样板.

我很想听听其他人对这个问题的看法.(我抱歉没有提供一个好的问题,可以回答而不是讨论:)

Chr*_*ris 2

我想我会使用委托模式 - 使用必须在构造函数中指定的单个 DateBean 成员创建一个 ImmutableDate 类:

public class ImmutableDate implements DateBean
{
   private DateBean delegate;

   public ImmutableDate(DateBean d)
   {
      this.delegate = d;
   }

   public Date getDate()
   {
      return delegate.getDate();
   }
}
Run Code Online (Sandbox Code Playgroud)

如果我需要在 DateBean d 上强制不变性,我只需在其上 new ImmutableDate(d) 即可。我本来可以很聪明,确保我没有委托代表,但你明白了。这避免了客户端尝试将其转换为可变对象的问题。这很像 JDK 对 Collections.unmodifyingMap() 等所做的事情。(但是,在这些情况下,仍然需要实现突变函数,并且编码为抛出运行时异常。如果您有一个没有突变者)。

这又是乏味的样板代码,但像 Eclipse 这样的优秀 IDE 只需点击几下鼠标就可以自动生成。

如果这是您最终对大量域对象执行的操作,您可能需要考虑使用动态代理甚至 AOP。那么,为任何对象构建代理、委托所有 get 方法并根据需要捕获或忽略 set 方法将相对容易。