原文引自:http://forum.javaeye.com/viewtopic.php?t=9035
偶們經常會遇到一些用戶需求, 需要實現一個區間類型的東東:
public class Entity {
private Date startDate;
private Date endDate;
private ......;
}
如項目的開始/結束時間, 人員的任職期間等等
但是如要比較這個對象和其他對象區間的關系, 就得寫一些惡心的code:
if(this.startDate > that.startDate && this.endDate < that.endDate)
if(this.startDate < that.startDate) ......
一堆的if else了.
或許你會覺得這些小東西這樣寫就可以了, 但是為了有一個更完美, 更好用的Domain Object, 是值得偶們在這些小細節上操勞的.
有一些現成的lib就是做這些東西的, 比如:
http://timeandmoney.sourceforge.net/
http://joda-time.sourceforge.net/
這里用timeandmoney lib為例子, 來介紹一下利用Hibernate的UserType來創建一個Domain Object
首先是一個業務對象:
java代碼: |
import com.domainlanguage.time.TimeInterval;
public class RecordLog extends Entity { private String description; private TimeInterval interval; //getters and setters...... }
|
然后是mapping文件:
xml代碼: |
<class name="RecordLog"> <id name="id"> <generator class="native"/> </id> <property name="description"/> <property name="interval" type="TimeIntervalType"> <column name="LOWER_LIMIT"/> <column name="INCLUDES_LOWER_LIMIT"/> <column name="UPPER_LIMIT"/> <column name="INCLUDES_UPPER_LIMIT"/> </property> </class>
|
一個操作它的Manager:
java代碼: |
public class Manager extends HibernateDaoSupport { public RecordLog load(Long id) { return (RecordLog) getHibernateTemplate().load(RecordLog.class, id); }
public void save(RecordLog log) { getHibernateTemplate().saveOrUpdate(log); } }
|
偶們先來看看它是怎么運行的:
java代碼: |
public void test() { TimePoint nov01 = TimePoint.atMidnightGMT(2004, 11, 01); TimePoint nov03 = TimePoint.atMidnightGMT(2004, 11, 03); TimePoint nov02 = TimePoint.atMidnightGMT(2004, 11, 02); TimePoint nov05 = TimePoint.atMidnightGMT(2004, 11, 05); RecordLog log1 = new RecordLog(); log1.setDescription("Record Log 1"); log1.setInterval(TimeInterval.closed(nov01, nov03)); RecordLog log2 = new RecordLog(); log2.setDescription("Record Log 2"); log2.setInterval(TimeInterval.closed(nov02, nov05)); //這里, 偶們只取交叉區間 //比原來的一堆if else簡潔多了吧? if(log1.getInterval().intersects(log2.getInterval())){ log1.setInterval(log1.getInterval().intersect(log2.getInterval())); } manager.save(log1);
RecordLog loaded = manager.load(log1.getId()); assertEquals("Record Log 1", loaded.getDescription()); assertEquals(nov02, loaded.getInterval().lowerLimit()); assertEquals(nov03, loaded.getInterval().upperLimit()); assertTrue(loaded.getInterval().includesLowerLimit()); assertTrue(loaded.getInterval().includesUpperLimit()); }
|
怎么樣, 是不是比原來的代碼簡單多了? 在背后干臟活,累活的就是這個TimeIntervalType和TimeAndMoney Lib:
代碼格式好難看阿, 只好用quote 寫道: |
public class TimeIntervalType implements UserType {
private static final int[] SQL_TYPES = new int[] { Hibernate.TIMESTAMP.sqlType(), Hibernate.BOOLEAN.sqlType(), Hibernate.TIMESTAMP.sqlType(), Hibernate.BOOLEAN.sqlType() };
public int[] sqlTypes() { return SQL_TYPES; }
public Class returnedClass() { return TimeInterval.class; }
public boolean equals(Object x, Object y) throws HibernateException { if (x == y) return true; if (x == null || y == null) return false; return ((TimeInterval) x).compareTo((TimeInterval) y) == 0; }
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { TimePoint lower = TimePoint.from((Timestamp) Hibernate.TIMESTAMP.nullSafeGet(rs, names[0])); boolean lowerIncluded = ((Boolean) Hibernate.BOOLEAN.nullSafeGet(rs, names[1])).booleanValue(); TimePoint upper = TimePoint.from((Timestamp) Hibernate.TIMESTAMP.nullSafeGet(rs, names[2])); boolean upperIncluded = ((Boolean) Hibernate.BOOLEAN.nullSafeGet(rs, names[3])).booleanValue(); return new TimeInterval(lower, lowerIncluded, upper, upperIncluded); }
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { TimeInterval interval = (TimeInterval) value; Hibernate.TIMESTAMP.nullSafeSet(st, new Timestamp(((TimePoint) interval.lowerLimit()).asJavaUtilDate().getTime()), index); Hibernate.BOOLEAN.nullSafeSet(st, new Boolean(interval.includesLowerLimit()), index + 1); Hibernate.TIMESTAMP.nullSafeSet(st, new Timestamp(((TimePoint) interval.upperLimit()).asJavaUtilDate().getTime()), index + 2); Hibernate.BOOLEAN.nullSafeSet(st, new Boolean(interval.includesUpperLimit()), index + 3); }
public Object deepCopy(Object value) throws HibernateException { if (value == null) return null; TimeInterval interval = (TimeInterval) value; return new TimeInterval((TimePoint) interval.lowerLimit(), interval.includesLowerLimit(), (TimePoint) interval.upperLimit(), interval .includesUpperLimit()); }
public boolean isMutable() { return true; }
}
|