Concurrency Java中的不可变bean

Concurrency Java中的不可变bean,concurrency,javabeans,immutability,Concurrency,Javabeans,Immutability,我非常好奇为java bean提供不变性的可能性(这里的bean指的是带有空构造函数的类,它为成员提供getter和setter)。显然,这些类不是一成不变的,它们用于从数据层传输值,这似乎是一个真正的问题 StackOverflow中提到了解决此问题的一种方法,称为“C#中的不可变对象模式”,其中对象在完全构建后被冻结。我有另一种方法,我真的很想听听人们的意见 该模式涉及两个类Immutable和Mutable,其中Mutable和Immutable都实现了一个接口,该接口提供了非变异bean

我非常好奇为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;
    }
}
这种方法允许使用反射构造bean(按照通常的约定),还允许我们在最近的时机转换为不可变的变量。不幸的是,每个bean显然有大量的样板文件

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

一些评论(不一定是问题):

  • Date类本身是可变的,因此您可以正确地复制它以保护不变性,但我个人更喜欢在构造函数中转换为long,并在getter中返回新的日期(longValue)
  • 两个getWhateverInstance()方法都返回DateBean,这将需要强制转换,因此最好更改接口以返回特定类型
  • 话虽如此,我倾向于只有两个类,一个是可变的,一个是不可变的,如果合适的话,共享一个公共(即get only)接口。如果您认为会有大量的来回转换,那么可以为这两个类添加一个复制构造函数
  • 我更喜欢不可变类将字段声明为final,以使编译器也强制执行不可变性
  • e、 g


    我使用接口和强制转换来控制bean的易变性。我看不出有什么理由用
    getImmutableInstance()
    getMutableInstance()
    等方法使域对象复杂化

    为什么不利用继承和抽象呢?e、 g

    public interface User{
    
      long getId();
    
      String getName();
    
      int getAge();
    
    }
    
    public interface MutableUser extends User{
    
      void setName(String name);
    
      void setAge(int age);
    
    }
    
    下面是代码的客户端将要执行的操作:

    public void validateUser(User user){
      if(user.getName() == null) ...
    }
    
    public void updateUserAge(MutableUser user, int age){
      user.setAge(age);
    }
    
    它回答了你的问题吗


    yc

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

    public class ImmutableDate implements DateBean
    {
       private DateBean delegate;
    
       public ImmutableDate(DateBean d)
       {
          this.delegate = d;
       }
    
       public Date getDate()
       {
          return delegate.getDate();
       }
    }
    
    如果我需要强制DateBean d具有不变性,我只需要在它上添加新的ImmutableDate(d)。我本可以很聪明,确保我没有委派代表,但你明白了。这避免了客户机试图将其转换为可变内容的问题。这与JDK对Collections.unmodifiableMap()等的处理非常相似(但是,在这些情况下,仍然必须实现变异函数,并对其进行编码以引发运行时异常。如果您有一个没有变异函数的基本接口,则更容易实现)

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


    如果你最终对很多领域对象做了一些事情,你可能想考虑使用动态代理或者甚至是AOP。因此,为任何对象构建代理、委派所有get方法以及适当地捕获或忽略set方法将相对容易。

    谢谢您的评论。我同意复制构造函数是对接口工厂方法的重大改进。关于最后成员的说明得到了很好的采纳。干杯。我想你的意思是让可变用户界面扩展用户界面?不用说,这仍然需要一个具体的类。不利的一面是,它让你变得“不可变”通过一个简单的强制转换(可能不是您想要的)来改变可变。虽然用户界面确实没有提供改变用户对象的方法,但从表面上看,它并不像我从这个模式中所要求的那样能够保证不可变性。尽管我认为您的方法确实提供了一个很好的工作解决方案类型(User)暗示不应该对用户进行变异。在许多情况下,这可能就足够了。谢谢,真的。这种方法的缺点是,使用强制转换很容易违反规则。内部代码大概不会违反它,但客户端的代码会。您所能做的最好的事情就是在如上所示的方法级别控制类型。这是一个非常好的主意。这非常适合这个问题。克里斯,干杯。如果这是DateBean中保存的日期对象,那么您必须在get上创建一个新的日期。否则,您可以通过ImmutableDate.getDate().set…修改日期。。。。
    public class ImmutableDate implements DateBean
    {
       private DateBean delegate;
    
       public ImmutableDate(DateBean d)
       {
          this.delegate = d;
       }
    
       public Date getDate()
       {
          return delegate.getDate();
       }
    }