Javaでドメインモデル設計の際重要になってくるequals()とhashCode()のオーバーライド.
これを自分で実装するのは結構めんどうくさいし,コードの可読性も決して高くはないのが通常だろうと思う.そんな時にお勧めなのはやはりApache CommonsのEqualsBuilderとHashCodeBuilderだろう.
サンプル
以下のようなトレードクラスがあったとする.
このクラスの主キーフィールドはtradeIdとeventIdとしよう.
equals()とhashCode()ではそれぞれEqualsBuilderとHashCodeBuilderを使って複合主キーを比較している.この例では非主キーのフィールドは比較をしていない.
import java.util.Date;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Trade {
private String tradeId;
private String eventId;
private Date settleDate;
private Date tradeDate;
private int counterPartyId;
public Trade( String tradeId, String eventId, Date settleDate, Date tradeDate, int counterPartyId ) {
this.tradeId = tradeId;
this.eventId = eventId;
this.settleDate = settleDate;
this.tradeDate = tradeDate;
this.counterPartyId = counterPartyId;
}
public boolean equals( Object obj ) {
boolean result = false;
if( obj instanceof Trade ) {
Trade other = (Trade)obj;
result = new EqualsBuilder().append( tradeId, other.getTradeId() )
.append( eventId, other.eventId )
.isEquals();
}
return result;
}
public int hashCode() {
return new HashCodeBuilder().append( tradeId )
.append( eventId ).toHashCode();
}
public String getTradeId() { return tradeId; }
public String getEventId() { return eventId; }
public Date getSettleDate() { return settleDate; }
public Date getTradeDate() { return tradeDate; }
public int getCounterPartyId() { return counterPartyId; }
}
それでもってこのTradeのequals()とhashCode()のテストクラスが以下の通り.
以下のテストで分かる通り,trd6は主キーが同じなのに非主キーフィールドは異なっているという異常ケースである.上記の実装ではこのような例外ケースには対応できていない.理想的には対応したほうがよい,と思うがとりあえずそれをするかどうかはプロジェクトの様々なvariablesを考慮した結果次第,だろうか.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.junit.Test;
import static org.junit.Assert.*;
public class BuilderSampleTest {
@Test
public void testEqualsAndHashCode() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy/MM/dd" );
Trade trd1 = new Trade( "TRD123", "21-123221", sdf.parse( "2012/03/04" ), sdf.parse( "2012/04/04" ), 565000 );
Trade trd2 = new Trade( "TRD238", "21-123250", sdf.parse( "2012/03/05" ), sdf.parse( "2012/04/04" ), 565000 );
Trade trd3 = new Trade( "TRD123", "21-123250", sdf.parse( "2012/03/05" ), sdf.parse( "2012/04/09" ), 565300 );
Trade trd4 = new Trade( "TRD126", "21-123221", sdf.parse( "2012/03/04" ), sdf.parse( "2012/04/04" ), 565000 );
Trade trd5 = new Trade( "TRD123", "21-123221", sdf.parse( "2012/03/04" ), sdf.parse( "2012/04/04" ), 565000 );
Trade trd6 = new Trade( "TRD123", "21-123221", sdf.parse( "2012/05/04" ), sdf.parse( "2012/06/04" ), 620000 );
// trd1 and trd2 - composite primary key different
assertTrue( !trd1.equals( trd2 ) );
// trd1 and trd3 - composite primary key different
assertTrue( !trd1.equals( trd3 ) );
// trd1 and trd4 - composite primary key different
assertTrue( !trd1.equals( trd4 ) );
// trd1 and trd5 - both composite primary key and non-key fields are same. Of course.
assertTrue( trd1.equals( trd5 ) );
// trd1 and trd6 - composite primary key is same but non-key fields are different - WHAT?!
assertTrue( trd1.equals( trd6 ) );
// trd1 and non-Trade object
assertTrue( !trd1.equals( new String() ) );
}
}
0 件のコメント:
コメントを投稿