Concurrency Java中的不可变bean
我非常好奇为java bean提供不变性的可能性(这里的bean指的是带有空构造函数的类,它为成员提供getter和setter)。显然,这些类不是一成不变的,它们用于从数据层传输值,这似乎是一个真正的问题 StackOverflow中提到了解决此问题的一种方法,称为“C#中的不可变对象模式”,其中对象在完全构建后被冻结。我有另一种方法,我真的很想听听人们的意见 该模式涉及两个类Immutable和Mutable,其中Mutable和Immutable都实现了一个接口,该接口提供了非变异bean方法 比如说Concurrency Java中的不可变bean,concurrency,javabeans,immutability,Concurrency,Javabeans,Immutability,我非常好奇为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显然有大量的样板文件
我很想听听其他人对这个问题的看法。(我很抱歉没有提供一个好问题,可以回答而不是讨论:)一些评论(不一定是问题):
我使用接口和强制转换来控制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();
}
}