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 件のコメント:
コメントを投稿