本讲把Address设计为不可变类.所谓不可变类,是指当创建了这种类的实例后,就不允许修改它的属性.在Java API中,所有的基本类型的包装类,如Integer和Long类,都是不可变类,java.lang.String也是不可变类.在创建用户自己的不可变类时,可以考虑采用以下的设计模式.
a.把属性定义为private final类型.
b.不对外公开用于修改属性的setXXX()方法.
c.只对外公开用于读取属性的getXXX()方法.
d.允许在构造函数中设置所有属性.
e.覆盖Object类的equals()和hashCode()方法
例1:
package mypack;
/**
* @author lfm
*
*/
import java.io.Serializable;
public class Address implements Serializable {
private final String province;
private final String city;
private final String street;
private final String zipcode;
public Address(String province, String city, String street, String zipcode) {
this.province = province;
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
public String getProvince() {
return this.province;
}
public String getCity() {
return this.city;
}
public String getStreet() {
return this.street;
}
public String getZipcode() {
return this.zipcode;
}
public boolean equals(Object o) {
if (this == null || !(o instanceof Address))
return false;
final Address address = (Address) o;
if (!province.equals(address.province))
return false;
if (!city.equals(address.city))
return false;
if (!street.equals(address.street))
return false;
if (!zipcode.equals(address.zipcode))
return false;
return true;
}
public int hashCode() {
int result;
result = (province == null ? 0 : province.hashCode());
result = 29 * result + (city == null ? 0 : city.hashCode());
result = 29 * result + (street == null ? 0 : street.hashCode());
result = 29 * result + (zipcode == null ? 0 : zipcode.hashCode());
return result;
}
}
由于Address类是不可变类,因此创建了Address类的实例后,就无法修改它的属性.如果要修改属性,必须使它引用一个新的Address实例.
例2是AddressUserType的源程序,它实现了UserType接口:
例2:
package mypack;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;
/**
* @author lfm
*
*/
public class AddressUserType implements UserType {
/* (非 Javadoc)
* @see net.sf.hibernate.UserType#sqlTypes()
*/
public int[] sqlTypes() {
// TODO 自动生成方法存根
return new int[]{Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR};
}
/* (非 Javadoc)
* @see net.sf.hibernate.UserType#returnedClass()
*/
public Class returnedClass() {
// TODO 自动生成方法存根
return Address.class;
}
/* (非 Javadoc)
* @see net.sf.hibernate.UserType#equals(java.lang.Object, java.lang.Object)
*/
public boolean equals(Object x, Object y) throws HibernateException {
// TODO 自动生成方法存根
if(x == y)
return true;
if(x == null || y == null)
return false;
return x.equals(y);
}
/* (非 Javadoc)
* @see net.sf.hibernate.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
// TODO 自动生成方法存根
if(rs.wasNull())
return null;
String province = rs.getString(names[0]);
String city = rs.getString(names[1]);
String street = rs.getString(names[2]);
String zipcode = rs.getString(names[3]);
return new Address(province, city, street, zipcode);
}
/* (非 Javadoc)
* @see net.sf.hibernate.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement statement, Object value, int index)
throws HibernateException, SQLException {
// TODO 自动生成方法存根
if(value == null) {
statement.setNull(index, Types.VARCHAR);
statement.setNull(index + 1, Types.VARCHAR);
statement.setNull(index + 2, Types.VARCHAR);
statement.setNull(index + 3, Types.VARCHAR);
}else{
Address obj = (Address)value;
statement.setString(index, obj.getProvince());
statement.setString(index + 1, obj.getCity());
statement.setString(index + 2, obj.getStreet());
statement.setString(index + 3, obj.getZipcode());
}
}
/* (非 Javadoc)
* @see net.sf.hibernate.UserType#deepCopy(java.lang.Object)
*/
public Object deepCopy(Object value) throws HibernateException {
// TODO 自动生成方法存根
return value;
}
/* (非 Javadoc)
* @see net.sf.hibernate.UserType#isMutable()
*/
public boolean isMutable() {
// TODO 自动生成方法存根
return false;
}
}
创建了以上的AddressUserType后,就可以按以下方式映射属性了:
<property name="address" type="mypack.AddressUserType">
<column name="HOME_STREET" length="15"/>
<column name="HOME_CITY" length="15"/>
<column name="HOME_PROVINCE" length="15"/>
<column name="HOME_ZIPCODE" length="6"/>
</property>
Hibernate组件和用户自定义类型都是值类型,在某些情况下能够完成同样的功能,到底选择何种方式,取决于用户自己的喜好.总的来说,Hibernate组件采用的是XML配置方式,因此具有较好的可维护性.自定义类型采用的是编程方式,能够完成更加复杂灵活的映射.